|
|
|
/*
|
|
|
|
Copyright (C) 2005 by Jasem Mutlaq
|
|
|
|
|
|
|
|
Based on V4L 2 Example
|
|
|
|
http://v4l2spec.bytesex.org/spec-single/v4l2.html#CAPTURE-EXAMPLE
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <asm/types.h> /* for videodev2.h */
|
|
|
|
|
|
|
|
#include "ccvt.h"
|
|
|
|
#include "v4l2_base.h"
|
|
|
|
#include "../eventloop.h"
|
|
|
|
#include "../indidevapi.h"
|
|
|
|
|
|
|
|
#define ERRMSGSIZ 1024
|
|
|
|
|
|
|
|
#define CLEAR(x) memset (&(x), 0, sizeof (x))
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
V4L2_Base::V4L2_Base()
|
|
|
|
{
|
|
|
|
frameRate=10;
|
|
|
|
selectCallBackID = -1;
|
|
|
|
dropFrame = false;
|
|
|
|
|
|
|
|
xmax = xmin = 160;
|
|
|
|
ymax = ymin = 120;
|
|
|
|
|
|
|
|
io = IO_METHOD_MMAP;
|
|
|
|
fd = -1;
|
|
|
|
buffers = NULL;
|
|
|
|
n_buffers = 0;
|
|
|
|
|
|
|
|
YBuf = NULL;
|
|
|
|
UBuf = NULL;
|
|
|
|
VBuf = NULL;
|
|
|
|
colorBuffer = NULL;
|
|
|
|
rgb24_buffer = NULL;
|
|
|
|
callback = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
V4L2_Base::~V4L2_Base()
|
|
|
|
{
|
|
|
|
|
|
|
|
delete (YBuf);
|
|
|
|
delete (UBuf);
|
|
|
|
delete (VBuf);
|
|
|
|
delete (colorBuffer);
|
|
|
|
delete (rgb24_buffer);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::xioctl(int fd, int request, void *arg)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
do r = ioctl (fd, request, arg);
|
|
|
|
while (-1 == r && EINTR == errno);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::errno_exit(const char *s, char *errmsg)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s error %d, %s\n",
|
|
|
|
s, errno, strerror (errno));
|
|
|
|
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "%s error %d, %s\n", s, errno, strerror (errno));
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::connectCam(const char * devpath, char *errmsg , int pixelFormat , int width , int height )
|
|
|
|
{
|
|
|
|
frameRate=10;
|
|
|
|
selectCallBackID = -1;
|
|
|
|
dropFrame = false;
|
|
|
|
|
|
|
|
if (open_device (devpath, errmsg) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (init_device(errmsg, pixelFormat, width, height) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
cerr << "V4L 2 - All successful, returning\n";
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::disconnectCam()
|
|
|
|
{
|
|
|
|
char errmsg[ERRMSGSIZ];
|
|
|
|
delete YBuf;
|
|
|
|
delete UBuf;
|
|
|
|
delete VBuf;
|
|
|
|
YBuf = UBuf = VBuf = NULL;
|
|
|
|
|
|
|
|
if (selectCallBackID != -1)
|
|
|
|
rmCallback(selectCallBackID);
|
|
|
|
|
|
|
|
stop_capturing (errmsg);
|
|
|
|
|
|
|
|
uninit_device (errmsg);
|
|
|
|
|
|
|
|
close_device ();
|
|
|
|
|
|
|
|
fprintf(stderr, "Disconnect cam\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::read_frame(char *errmsg)
|
|
|
|
{
|
|
|
|
struct v4l2_buffer buf;
|
|
|
|
unsigned int i;
|
|
|
|
//cerr << "in read Frame" << endl;
|
|
|
|
|
|
|
|
switch (io) {
|
|
|
|
case IO_METHOD_READ:
|
|
|
|
if (-1 == read (fd, buffers[0].start, buffers[0].length)) {
|
|
|
|
switch (errno) {
|
|
|
|
case EAGAIN:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case EIO:
|
|
|
|
/* Could ignore EIO, see spec. */
|
|
|
|
|
|
|
|
/* fall through */
|
|
|
|
|
|
|
|
default:
|
|
|
|
return errno_exit ("read", errmsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//process_image (buffers[0].start);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_MMAP:
|
|
|
|
CLEAR (buf);
|
|
|
|
|
|
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
buf.memory = V4L2_MEMORY_MMAP;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_DTQBUF, &buf)) {
|
|
|
|
switch (errno) {
|
|
|
|
case EAGAIN:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case EIO:
|
|
|
|
/* Could ignore EIO, see spec. */
|
|
|
|
|
|
|
|
/* fall through */
|
|
|
|
|
|
|
|
default:
|
|
|
|
return errno_exit ("VIDIOC_DTQBUF", errmsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert (buf.index < n_buffers);
|
|
|
|
|
|
|
|
switch (fmt.fmt.pix.pixelformat)
|
|
|
|
{
|
|
|
|
case V4L2_PIX_FMT_YUV420:
|
|
|
|
memcpy(YBuf,((unsigned char *) buffers[buf.index].start), fmt.fmt.pix.width * fmt.fmt.pix.height);
|
|
|
|
memcpy(UBuf,((unsigned char *) buffers[buf.index].start) + fmt.fmt.pix.width * fmt.fmt.pix.height, (fmt.fmt.pix.width/2) * (fmt.fmt.pix.height/2));
|
|
|
|
memcpy(VBuf,((unsigned char *) buffers[buf.index].start) + fmt.fmt.pix.width * fmt.fmt.pix.height + (fmt.fmt.pix.width/2) * (fmt.fmt.pix.height/2), (fmt.fmt.pix.width/2) * (fmt.fmt.pix.width/2));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V4L2_PIX_FMT_YUYV:
|
|
|
|
ccvt_yuyv_420p( fmt.fmt.pix.width , fmt.fmt.pix.height, buffers[buf.index].start, YBuf, UBuf, VBuf);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V4L2_PIX_FMT_RGB24:
|
|
|
|
RGB2YUV(fmt.fmt.pix.width, fmt.fmt.pix.height, buffers[buf.index].start, YBuf, UBuf, VBuf, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V4L2_PIX_FMT_SBGGR8:
|
|
|
|
bayer2rgb24(rgb24_buffer, ((unsigned char *) buffers[buf.index].start), fmt.fmt.pix.width, fmt.fmt.pix.height);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_TQBUF, &buf))
|
|
|
|
return errno_exit ("VIDIOC_TQBUF", errmsg);
|
|
|
|
|
|
|
|
if (dropFrame)
|
|
|
|
{
|
|
|
|
dropFrame = false;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call provided callback function if any */
|
|
|
|
if (callback)
|
|
|
|
(*callback)(uptr);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_USERPTR:
|
|
|
|
CLEAR (buf);
|
|
|
|
|
|
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
buf.memory = V4L2_MEMORY_USERPTR;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_DTQBUF, &buf)) {
|
|
|
|
switch (errno) {
|
|
|
|
case EAGAIN:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case EIO:
|
|
|
|
/* Could ignore EIO, see spec. */
|
|
|
|
|
|
|
|
/* fall through */
|
|
|
|
|
|
|
|
default:
|
|
|
|
errno_exit ("VIDIOC_DTQBUF", errmsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < n_buffers; ++i)
|
|
|
|
if (buf.m.userptr == (unsigned long) buffers[i].start
|
|
|
|
&& buf.length == buffers[i].length)
|
|
|
|
break;
|
|
|
|
|
|
|
|
assert (i < n_buffers);
|
|
|
|
|
|
|
|
//process_image ((void *) buf.m.userptr);
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_TQBUF, &buf))
|
|
|
|
errno_exit ("VIDIOC_TQBUF", errmsg);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::stop_capturing(char *errmsg)
|
|
|
|
{
|
|
|
|
enum v4l2_buf_type type;
|
|
|
|
|
|
|
|
switch (io) {
|
|
|
|
case IO_METHOD_READ:
|
|
|
|
/* Nothing to do. */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_MMAP:
|
|
|
|
case IO_METHOD_USERPTR:
|
|
|
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
|
|
|
IERmCallback(selectCallBackID);
|
|
|
|
selectCallBackID = -1;
|
|
|
|
|
|
|
|
dropFrame = true;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
|
|
|
|
return errno_exit ("VIDIOC_STREAMOFF", errmsg);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::start_capturing(char * errmsg)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
enum v4l2_buf_type type;
|
|
|
|
|
|
|
|
switch (io) {
|
|
|
|
case IO_METHOD_READ:
|
|
|
|
/* Nothing to do. */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_MMAP:
|
|
|
|
for (i = 0; i < n_buffers; ++i) {
|
|
|
|
struct v4l2_buffer buf;
|
|
|
|
|
|
|
|
CLEAR (buf);
|
|
|
|
|
|
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
buf.memory = V4L2_MEMORY_MMAP;
|
|
|
|
buf.index = i;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_TQBUF, &buf))
|
|
|
|
return errno_exit ("VIDIOC_TQBUF", errmsg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
|
|
|
|
return errno_exit ("VIDIOC_STREAMON", errmsg);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
selectCallBackID = IEAddCallback(fd, newFrame, this);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_USERPTR:
|
|
|
|
for (i = 0; i < n_buffers; ++i) {
|
|
|
|
struct v4l2_buffer buf;
|
|
|
|
|
|
|
|
CLEAR (buf);
|
|
|
|
|
|
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
buf.memory = V4L2_MEMORY_USERPTR;
|
|
|
|
buf.m.userptr = (unsigned long) buffers[i].start;
|
|
|
|
buf.length = buffers[i].length;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_TQBUF, &buf))
|
|
|
|
return errno_exit ("VIDIOC_TQBUF", errmsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
|
|
|
|
return errno_exit ("VIDIOC_STREAMON", errmsg);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::newFrame(int /*fd*/, void *p)
|
|
|
|
{
|
|
|
|
char errmsg[ERRMSGSIZ];
|
|
|
|
|
|
|
|
( (V4L2_Base *) (p))->read_frame(errmsg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::uninit_device(char *errmsg)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (io) {
|
|
|
|
case IO_METHOD_READ:
|
|
|
|
free (buffers[0].start);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_MMAP:
|
|
|
|
for (unsigned int i = 0; i < n_buffers; ++i)
|
|
|
|
if (-1 == munmap (buffers[i].start, buffers[i].length))
|
|
|
|
return errno_exit ("munmap", errmsg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_USERPTR:
|
|
|
|
for (unsigned int i = 0; i < n_buffers; ++i)
|
|
|
|
free (buffers[i].start);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
free (buffers);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::init_read(unsigned int buffer_size)
|
|
|
|
{
|
|
|
|
buffers = (buffer *) calloc (1, sizeof (*buffers));
|
|
|
|
|
|
|
|
if (!buffers) {
|
|
|
|
fprintf (stderr, "Out of memory\n");
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
buffers[0].length = buffer_size;
|
|
|
|
buffers[0].start = malloc (buffer_size);
|
|
|
|
|
|
|
|
if (!buffers[0].start) {
|
|
|
|
fprintf (stderr, "Out of memory\n");
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::init_mmap(char *errmsg)
|
|
|
|
{
|
|
|
|
struct v4l2_requestbuffers req;
|
|
|
|
|
|
|
|
CLEAR (req);
|
|
|
|
|
|
|
|
req.count = 4;
|
|
|
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
req.memory = V4L2_MEMORY_MMAP;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
|
|
|
|
if (EINVAL == errno) {
|
|
|
|
fprintf (stderr, "%s does not support "
|
|
|
|
"memory mapping\n", dev_name);
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "%s does not support "
|
|
|
|
"memory mapping\n", dev_name);
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return errno_exit ("VIDIOC_REQBUFS", errmsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (req.count < 2) {
|
|
|
|
fprintf (stderr, "Insufficient buffer memory on %s\n",
|
|
|
|
dev_name);
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "Insufficient buffer memory on %s\n",
|
|
|
|
dev_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffers = (buffer *) calloc (req.count, sizeof (*buffers));
|
|
|
|
|
|
|
|
if (!buffers)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "buffers. Out of memory\n");
|
|
|
|
strncpy(errmsg, "buffers. Out of memory\n", ERRMSGSIZ);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
|
|
|
|
{
|
|
|
|
struct v4l2_buffer buf;
|
|
|
|
|
|
|
|
CLEAR (buf);
|
|
|
|
|
|
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
buf.memory = V4L2_MEMORY_MMAP;
|
|
|
|
buf.index = n_buffers;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
|
|
|
|
return errno_exit ("VIDIOC_QUERYBUF", errmsg);
|
|
|
|
|
|
|
|
buffers[n_buffers].length = buf.length;
|
|
|
|
buffers[n_buffers].start =
|
|
|
|
mmap (NULL /* start anywhere */,
|
|
|
|
buf.length,
|
|
|
|
PROT_READ | PROT_WRITE /* required */,
|
|
|
|
MAP_SHARED /* recommended */,
|
|
|
|
fd, buf.m.offset);
|
|
|
|
|
|
|
|
if (MAP_FAILED == buffers[n_buffers].start)
|
|
|
|
return errno_exit ("mmap", errmsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::init_userp(unsigned int buffer_size)
|
|
|
|
{
|
|
|
|
struct v4l2_requestbuffers req;
|
|
|
|
char errmsg[ERRMSGSIZ];
|
|
|
|
|
|
|
|
CLEAR (req);
|
|
|
|
|
|
|
|
req.count = 4;
|
|
|
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
req.memory = V4L2_MEMORY_USERPTR;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
|
|
|
|
if (EINVAL == errno) {
|
|
|
|
fprintf (stderr, "%s does not support "
|
|
|
|
"user pointer i/o\n", dev_name);
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
} else {
|
|
|
|
errno_exit ("VIDIOC_REQBUFS", errmsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buffers = (buffer *) calloc (4, sizeof (*buffers));
|
|
|
|
|
|
|
|
if (!buffers) {
|
|
|
|
fprintf (stderr, "Out of memory\n");
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
|
|
|
|
buffers[n_buffers].length = buffer_size;
|
|
|
|
buffers[n_buffers].start = malloc (buffer_size);
|
|
|
|
|
|
|
|
if (!buffers[n_buffers].start) {
|
|
|
|
fprintf (stderr, "Out of memory\n");
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::init_device(char *errmsg, int pixelFormat , int width, int height)
|
|
|
|
{
|
|
|
|
unsigned int min;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap))
|
|
|
|
{
|
|
|
|
if (EINVAL == errno) {
|
|
|
|
fprintf (stderr, "%s is no V4L2 device\n",
|
|
|
|
dev_name);
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "%s is no V4L2 device\n", dev_name);
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return errno_exit ("VIDIOC_QUERYCAP", errmsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s is no video capture device\n",
|
|
|
|
dev_name);
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "%s is no video capture device\n", dev_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (io)
|
|
|
|
{
|
|
|
|
case IO_METHOD_READ:
|
|
|
|
if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
|
|
|
|
fprintf (stderr, "%s does not support read i/o\n",
|
|
|
|
dev_name);
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "%s does not support read i/o\n",
|
|
|
|
dev_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_MMAP:
|
|
|
|
case IO_METHOD_USERPTR:
|
|
|
|
if (!(cap.capabilities & V4L2_CAP_STREAMING))
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s does not support streaming i/o\n",
|
|
|
|
dev_name);
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "%s does not support streaming i/o\n",
|
|
|
|
dev_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Select video input, video standard and tune here. */
|
|
|
|
|
|
|
|
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
|
|
|
|
/* Errors ignored. */
|
|
|
|
}
|
|
|
|
|
|
|
|
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
crop.c = cropcap.defrect; /* reset to default */
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
|
|
|
|
switch (errno) {
|
|
|
|
case EINVAL:
|
|
|
|
/* Cropping not supported. */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Errors ignored. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CLEAR (fmt);
|
|
|
|
|
|
|
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
fmt.fmt.pix.width = width;
|
|
|
|
fmt.fmt.pix.height = height;
|
|
|
|
fmt.fmt.pix.pixelformat = pixelFormat;
|
|
|
|
//fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
|
|
|
|
return errno_exit ("VIDIOC_S_FMT", errmsg);
|
|
|
|
|
|
|
|
/* Note VIDIOC_S_FMT may change width and height. */
|
|
|
|
|
|
|
|
/* Buggy driver paranoia. */
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* Let's get the actual size */
|
|
|
|
CLEAR(fmt);
|
|
|
|
|
|
|
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_G_FMT, &fmt))
|
|
|
|
return errno_exit ("VIDIOC_G_FMT", errmsg);
|
|
|
|
|
|
|
|
cerr << "width: " << fmt.fmt.pix.width << " - height: " << fmt.fmt.pix.height << endl;
|
|
|
|
|
|
|
|
switch (pixelFormat)
|
|
|
|
{
|
|
|
|
case V4L2_PIX_FMT_YUV420:
|
|
|
|
cerr << "pixel format: V4L2_PIX_FMT_YUV420" << endl;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V4L2_PIX_FMT_YUYV:
|
|
|
|
cerr << "pixel format: V4L2_PIX_FMT_YUYV" << endl;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V4L2_PIX_FMT_RGB24:
|
|
|
|
cerr << "pixel format: V4L2_PIX_FMT_RGB24" << endl;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V4L2_PIX_FMT_SBGGR8:
|
|
|
|
cerr << "pixel format: V4L2_PIX_FMT_SBGGR8" << endl;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
findMinMax();
|
|
|
|
|
|
|
|
allocBuffers();
|
|
|
|
|
|
|
|
switch (io)
|
|
|
|
{
|
|
|
|
case IO_METHOD_READ:
|
|
|
|
init_read (fmt.fmt.pix.sizeimage);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_MMAP:
|
|
|
|
return init_mmap(errmsg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IO_METHOD_USERPTR:
|
|
|
|
init_userp (fmt.fmt.pix.sizeimage);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::close_device(void)
|
|
|
|
{
|
|
|
|
char errmsg[ERRMSGSIZ];
|
|
|
|
|
|
|
|
if (-1 == close (fd))
|
|
|
|
errno_exit ("close", errmsg);
|
|
|
|
|
|
|
|
fd = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::open_device(const char *devpath, char *errmsg)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
strncpy(dev_name, devpath, 64);
|
|
|
|
|
|
|
|
if (-1 == stat (dev_name, &st)) {
|
|
|
|
fprintf (stderr, "Cannot identify '%s': %d, %s\n",
|
|
|
|
dev_name, errno, strerror (errno));
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "Cannot identify '%s': %d, %s\n",
|
|
|
|
dev_name, errno, strerror (errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISCHR (st.st_mode))
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s is no device\n", dev_name);
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "%s is no device\n", dev_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
|
|
|
|
|
|
|
|
if (-1 == fd)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "Cannot open '%s': %d, %s\n",
|
|
|
|
dev_name, errno, strerror (errno));
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "Cannot open '%s': %d, %s\n",
|
|
|
|
dev_name, errno, strerror (errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int V4L2_Base::getWidth()
|
|
|
|
{
|
|
|
|
return fmt.fmt.pix.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::getHeight()
|
|
|
|
{
|
|
|
|
return fmt.fmt.pix.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::setFPS(int fps)
|
|
|
|
{
|
|
|
|
frameRate = 15;//fps;
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::getFPS()
|
|
|
|
{
|
|
|
|
return 15;
|
|
|
|
}
|
|
|
|
|
|
|
|
char * V4L2_Base::getDeviceName()
|
|
|
|
{
|
|
|
|
return ((char *) cap.card);
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::allocBuffers()
|
|
|
|
{
|
|
|
|
delete (YBuf); YBuf = NULL;
|
|
|
|
delete (UBuf); UBuf = NULL;
|
|
|
|
delete (VBuf); VBuf = NULL;
|
|
|
|
delete (colorBuffer); colorBuffer = NULL;
|
|
|
|
delete (rgb24_buffer); rgb24_buffer = NULL;
|
|
|
|
|
|
|
|
YBuf= new unsigned char[ fmt.fmt.pix.width * fmt.fmt.pix.height];
|
|
|
|
UBuf= new unsigned char[ fmt.fmt.pix.width * fmt.fmt.pix.height];
|
|
|
|
VBuf= new unsigned char[ fmt.fmt.pix.width * fmt.fmt.pix.height];
|
|
|
|
colorBuffer = new unsigned char[fmt.fmt.pix.width * fmt.fmt.pix.height * 4];
|
|
|
|
|
|
|
|
if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
|
|
|
|
rgb24_buffer = new unsigned char[fmt.fmt.pix.width * fmt.fmt.pix.height * 3];
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::getMaxMinSize(int & x_max, int & y_max, int & x_min, int & y_min)
|
|
|
|
{
|
|
|
|
x_max = xmax; y_max = ymax; x_min = xmin; y_min = ymin;
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::setSize(int x, int y)
|
|
|
|
{
|
|
|
|
char errmsg[ERRMSGSIZ];
|
|
|
|
int oldW, oldH;
|
|
|
|
|
|
|
|
oldW = fmt.fmt.pix.width;
|
|
|
|
oldH = fmt.fmt.pix.height;
|
|
|
|
|
|
|
|
fmt.fmt.pix.width = x;
|
|
|
|
fmt.fmt.pix.height = y;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
|
|
|
|
{
|
|
|
|
fmt.fmt.pix.width = oldW;
|
|
|
|
fmt.fmt.pix.height = oldH;
|
|
|
|
return errno_exit ("VIDIOC_S_FMT", errmsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PWC bug? It seems that setting the "wrong" width and height will mess something in the driver.
|
|
|
|
Only 160x120, 320x280, and 640x480 are accepted. If I try to set it for example to 300x200, it wii
|
|
|
|
get set to 320x280, which is fine, but then the video information is messed up for some reason. */
|
|
|
|
xioctl (fd, VIDIOC_S_FMT, &fmt);
|
|
|
|
|
|
|
|
|
|
|
|
allocBuffers();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::setContrast(int val)
|
|
|
|
{
|
|
|
|
/*picture_.contrast=val;
|
|
|
|
updatePictureSettings();*/
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::getContrast()
|
|
|
|
{
|
|
|
|
return 255;//picture_.contrast;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::setBrightness(int val)
|
|
|
|
{
|
|
|
|
/*picture_.brightness=val;
|
|
|
|
updatePictureSettings();*/
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::getBrightness()
|
|
|
|
{
|
|
|
|
return 255;//picture_.brightness;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::setColor(int val)
|
|
|
|
{
|
|
|
|
/*picture_.colour=val;
|
|
|
|
updatePictureSettings();*/
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::getColor()
|
|
|
|
{
|
|
|
|
return 255; //picture_.colour;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::setHue(int val)
|
|
|
|
{
|
|
|
|
/*picture_.hue=val;
|
|
|
|
updatePictureSettings();*/
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::getHue()
|
|
|
|
{
|
|
|
|
return 255;//picture_.hue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::setWhiteness(int val)
|
|
|
|
{
|
|
|
|
/*picture_.whiteness=val;
|
|
|
|
updatePictureSettings();*/
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::getWhiteness()
|
|
|
|
{
|
|
|
|
return 255;//picture_.whiteness;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::setPictureSettings()
|
|
|
|
{
|
|
|
|
/*if (ioctl(device_, VIDIOCSPICT, &picture_) ) {
|
|
|
|
cerr << "updatePictureSettings" << endl;
|
|
|
|
}
|
|
|
|
ioctl(device_, VIDIOCGPICT, &picture_);*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::getPictureSettings()
|
|
|
|
{
|
|
|
|
/*if (ioctl(device_, VIDIOCGPICT, &picture_) )
|
|
|
|
{
|
|
|
|
cerr << "refreshPictureSettings" << endl;
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char * V4L2_Base::getY()
|
|
|
|
{
|
|
|
|
if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
|
|
|
|
RGB2YUV(fmt.fmt.pix.width, fmt.fmt.pix.height, rgb24_buffer, YBuf, UBuf, VBuf, 0);
|
|
|
|
|
|
|
|
return YBuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char * V4L2_Base::getU()
|
|
|
|
{
|
|
|
|
return UBuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char * V4L2_Base::getV()
|
|
|
|
{
|
|
|
|
return VBuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char * V4L2_Base::getColorBuffer()
|
|
|
|
{
|
|
|
|
//cerr << "in get color buffer " << endl;
|
|
|
|
|
|
|
|
switch (fmt.fmt.pix.pixelformat)
|
|
|
|
{
|
|
|
|
case V4L2_PIX_FMT_YUV420:
|
|
|
|
ccvt_420p_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height,
|
|
|
|
buffers[0].start, (void*)colorBuffer);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V4L2_PIX_FMT_YUYV:
|
|
|
|
ccvt_yuyv_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height,
|
|
|
|
buffers[0].start, (void*)colorBuffer);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V4L2_PIX_FMT_RGB24:
|
|
|
|
ccvt_rgb24_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height,
|
|
|
|
buffers[0].start, (void*)colorBuffer);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case V4L2_PIX_FMT_SBGGR8:
|
|
|
|
ccvt_rgb24_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height,
|
|
|
|
rgb24_buffer, (void*)colorBuffer);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return colorBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::registerCallback(WPF *fp, void *ud)
|
|
|
|
{
|
|
|
|
callback = fp;
|
|
|
|
uptr = ud;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::findMinMax()
|
|
|
|
{
|
|
|
|
char errmsg[ERRMSGSIZ];
|
|
|
|
struct v4l2_format tryfmt;
|
|
|
|
CLEAR(tryfmt);
|
|
|
|
|
|
|
|
xmin = xmax = fmt.fmt.pix.width;
|
|
|
|
ymin = ymax = fmt.fmt.pix.height;
|
|
|
|
|
|
|
|
tryfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
tryfmt.fmt.pix.width = 10;
|
|
|
|
tryfmt.fmt.pix.height = 10;
|
|
|
|
tryfmt.fmt.pix.pixelformat = fmt.fmt.pix.pixelformat;
|
|
|
|
tryfmt.fmt.pix.field = fmt.fmt.pix.field;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_TRY_FMT, &tryfmt))
|
|
|
|
{
|
|
|
|
errno_exit ("VIDIOC_TRY_FMT 1", errmsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmin = tryfmt.fmt.pix.width;
|
|
|
|
ymin = tryfmt.fmt.pix.height;
|
|
|
|
|
|
|
|
tryfmt.fmt.pix.width = 1600;
|
|
|
|
tryfmt.fmt.pix.height = 1200;
|
|
|
|
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_TRY_FMT, &tryfmt))
|
|
|
|
{
|
|
|
|
errno_exit ("VIDIOC_TRY_FMT 2", errmsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmax = tryfmt.fmt.pix.width;
|
|
|
|
ymax = tryfmt.fmt.pix.height;
|
|
|
|
|
|
|
|
cerr << "Min X: " << xmin << " - Max X: " << xmax << " - Min Y: " << ymin << " - Max Y: " << ymax << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::enumerate_ctrl (void)
|
|
|
|
{
|
|
|
|
char errmsg[ERRMSGSIZ];
|
|
|
|
CLEAR(queryctrl);
|
|
|
|
|
|
|
|
for (queryctrl.id = V4L2_CID_BASE; queryctrl.id < V4L2_CID_LASTP1; queryctrl.id++)
|
|
|
|
{
|
|
|
|
if (0 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
|
|
|
|
{
|
|
|
|
cerr << "Control " << queryctrl.name << endl;
|
|
|
|
|
|
|
|
if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cerr << "Control " << queryctrl.name << endl;
|
|
|
|
|
|
|
|
if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
|
|
|
|
enumerate_menu ();
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
if (errno == EINVAL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
errno_exit("VIDIOC_QUERYCTRL", errmsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (queryctrl.id = V4L2_CID_PRIVATE_BASE; ; queryctrl.id++)
|
|
|
|
{
|
|
|
|
if (0 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
|
|
|
|
{
|
|
|
|
cerr << "Private Control " << queryctrl.name << endl;
|
|
|
|
|
|
|
|
if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
|
|
|
|
enumerate_menu ();
|
|
|
|
} else {
|
|
|
|
if (errno == EINVAL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
errno_exit ("VIDIOC_QUERYCTRL", errmsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void V4L2_Base::enumerate_menu (void)
|
|
|
|
{
|
|
|
|
char errmsg[ERRMSGSIZ];
|
|
|
|
cerr << " Menu items:" << endl;
|
|
|
|
|
|
|
|
CLEAR(querymenu);
|
|
|
|
querymenu.id = queryctrl.id;
|
|
|
|
|
|
|
|
for (querymenu.index = queryctrl.minimum; querymenu.index <= queryctrl.maximum; querymenu.index++)
|
|
|
|
{
|
|
|
|
if (0 == xioctl (fd, VIDIOC_QUERYMENU, &querymenu))
|
|
|
|
{
|
|
|
|
cerr << " " << querymenu.name << endl;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
errno_exit("VIDIOC_QUERYMENU", errmsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::query_ctrl(unsigned int ctrl_id, double & ctrl_min, double & ctrl_max, double & ctrl_step, double & ctrl_value, char *errmsg)
|
|
|
|
{
|
|
|
|
|
|
|
|
struct v4l2_control control;
|
|
|
|
|
|
|
|
CLEAR(queryctrl);
|
|
|
|
|
|
|
|
queryctrl.id = ctrl_id;
|
|
|
|
|
|
|
|
if (-1 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
|
|
|
|
{
|
|
|
|
if (errno != EINVAL)
|
|
|
|
return errno_exit ("VIDIOC_QUERYCTRL", errmsg);
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cerr << "#" << ctrl_id << " is not supported" << endl;
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "# %d is not supported", ctrl_id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
|
|
|
|
{
|
|
|
|
cerr << "#" << ctrl_id << " is disabled" << endl;
|
|
|
|
snprintf(errmsg, ERRMSGSIZ, "# %d is disabled", ctrl_id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrl_min = queryctrl.minimum;
|
|
|
|
ctrl_max = queryctrl.maximum;
|
|
|
|
ctrl_step = queryctrl.step;
|
|
|
|
ctrl_value = queryctrl.default_value;
|
|
|
|
|
|
|
|
/* Get current value */
|
|
|
|
CLEAR(control);
|
|
|
|
control.id = ctrl_id;
|
|
|
|
|
|
|
|
if (0 == xioctl(fd, VIDIOC_G_CTRL, &control))
|
|
|
|
ctrl_value = control.value;
|
|
|
|
|
|
|
|
cerr << queryctrl.name << " -- min: " << ctrl_min << " max: " << ctrl_max << " step: " << ctrl_step << " value: " << ctrl_value << endl;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::queryINTControls(INumberVectorProperty *nvp)
|
|
|
|
{
|
|
|
|
struct v4l2_control control;
|
|
|
|
char errmsg[ERRMSGSIZ];
|
|
|
|
CLEAR(queryctrl);
|
|
|
|
INumber *numbers = NULL;
|
|
|
|
unsigned int *num_ctrls = NULL;
|
|
|
|
int nnum=0;
|
|
|
|
|
|
|
|
for (queryctrl.id = V4L2_CID_BASE; queryctrl.id < V4L2_CID_LASTP1; queryctrl.id++)
|
|
|
|
{
|
|
|
|
if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
|
|
|
|
{
|
|
|
|
if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
|
|
|
|
{
|
|
|
|
cerr << queryctrl.name << " is disabled." << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queryctrl.type == V4L2_CTRL_TYPE_INTEGER)
|
|
|
|
{
|
|
|
|
numbers = (numbers == NULL) ? (INumber *) malloc (sizeof(INumber)) :
|
|
|
|
(INumber *) realloc (numbers, (nnum+1) * sizeof (INumber));
|
|
|
|
|
|
|
|
num_ctrls = (num_ctrls == NULL) ? (unsigned int *) malloc (sizeof (unsigned int)) :
|
|
|
|
(unsigned int *) realloc (num_ctrls, (nnum+1) * sizeof (unsigned int));
|
|
|
|
|
|
|
|
strncpy(numbers[nnum].name, ((char *) queryctrl.name) , MAXINDINAME);
|
|
|
|
strncpy(numbers[nnum].label, ((char *) queryctrl.name), MAXINDILABEL);
|
|
|
|
strncpy(numbers[nnum].format, "%0.f", MAXINDIFORMAT);
|
|
|
|
numbers[nnum].min = queryctrl.minimum;
|
|
|
|
numbers[nnum].max = queryctrl.maximum;
|
|
|
|
numbers[nnum].step = queryctrl.step;
|
|
|
|
numbers[nnum].value = queryctrl.default_value;
|
|
|
|
|
|
|
|
/* Get current value if possible */
|
|
|
|
CLEAR(control);
|
|
|
|
control.id = queryctrl.id;
|
|
|
|
if (0 == xioctl(fd, VIDIOC_G_CTRL, &control))
|
|
|
|
numbers[nnum].value = control.value;
|
|
|
|
|
|
|
|
/* Store ID info in INumber. This is the first time ever I make use of aux0!! */
|
|
|
|
num_ctrls[nnum] = queryctrl.id;
|
|
|
|
|
|
|
|
cerr << queryctrl.name << " -- min: " << queryctrl.minimum << " max: " << queryctrl.maximum << " step: " << queryctrl.step << " value: " << numbers[nnum].value << endl;
|
|
|
|
|
|
|
|
nnum++;
|
|
|
|
|
|
|
|
}
|
|
|
|
} else if (errno != EINVAL)
|
|
|
|
return errno_exit ("VIDIOC_QUERYCTRL", errmsg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (queryctrl.id = V4L2_CID_PRIVATE_BASE; ; queryctrl.id++)
|
|
|
|
{
|
|
|
|
if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
|
|
|
|
{
|
|
|
|
if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
|
|
|
|
{
|
|
|
|
cerr << queryctrl.name << " is disabled." << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queryctrl.type == V4L2_CTRL_TYPE_INTEGER)
|
|
|
|
{
|
|
|
|
numbers = (numbers == NULL) ? (INumber *) malloc (sizeof(INumber)) :
|
|
|
|
(INumber *) realloc (numbers, (nnum+1) * sizeof (INumber));
|
|
|
|
|
|
|
|
num_ctrls = (num_ctrls == NULL) ? (unsigned int *) malloc (sizeof (unsigned int)) :
|
|
|
|
(unsigned int *) realloc (num_ctrls, (nnum+1) * sizeof (unsigned int));
|
|
|
|
|
|
|
|
strncpy(numbers[nnum].name, ((char *) queryctrl.name) , MAXINDINAME);
|
|
|
|
strncpy(numbers[nnum].label, ((char *) queryctrl.name), MAXINDILABEL);
|
|
|
|
strncpy(numbers[nnum].format, "%0.f", MAXINDIFORMAT);
|
|
|
|
numbers[nnum].min = queryctrl.minimum;
|
|
|
|
numbers[nnum].max = queryctrl.maximum;
|
|
|
|
numbers[nnum].step = queryctrl.step;
|
|
|
|
numbers[nnum].value = queryctrl.default_value;
|
|
|
|
|
|
|
|
/* Get current value if possible */
|
|
|
|
CLEAR(control);
|
|
|
|
control.id = queryctrl.id;
|
|
|
|
if (0 == xioctl(fd, VIDIOC_G_CTRL, &control))
|
|
|
|
numbers[nnum].value = control.value;
|
|
|
|
|
|
|
|
/* Store ID info in INumber. This is the first time ever I make use of aux0!! */
|
|
|
|
num_ctrls[nnum] = queryctrl.id;
|
|
|
|
|
|
|
|
nnum++;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Store numbers in aux0 */
|
|
|
|
for (int i=0; i < nnum; i++)
|
|
|
|
numbers[i].aux0 = &num_ctrls[i];
|
|
|
|
|
|
|
|
nvp->np = numbers;
|
|
|
|
nvp->nnp = nnum;
|
|
|
|
|
|
|
|
return nnum;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int V4L2_Base::setINTControl(unsigned int ctrl_id, double new_value, char *errmsg)
|
|
|
|
{
|
|
|
|
struct v4l2_control control;
|
|
|
|
|
|
|
|
CLEAR(control);
|
|
|
|
|
|
|
|
cerr << "The id is " << ctrl_id << " new value is " << new_value << endl;
|
|
|
|
|
|
|
|
control.id = ctrl_id;
|
|
|
|
control.value = (int) new_value;
|
|
|
|
|
|
|
|
if (-1 == xioctl(fd, VIDIOC_S_CTRL, &control))
|
|
|
|
return errno_exit ("VIDIOC_S_CTRL", errmsg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|