extract V4L2 wrapper

pull/33/head
Michel Promonet 9 years ago
parent b3010a157c
commit 812522473e

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "v4l2wrapper"]
path = v4l2wrapper
url = https://github.com/mpromonet/v4l2wrapper

@ -11,6 +11,8 @@ set(CMAKE_CXX_FLAGS "-Wall")
# define executable to build
include_directories("${PROJECT_BINARY_DIR}/inc")
aux_source_directory(src SRC_FILES)
include_directories("${PROJECT_BINARY_DIR}/v4l2wrapper/inc")
aux_source_directory(v4l2wrapper/src SRC_FILES)
add_executable(${PROJECT_NAME} ${SRC_FILES})
# LOG4CPP

@ -1,76 +0,0 @@
/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** V4l2Capture.h
**
** V4L2 wrapper
**
** -------------------------------------------------------------------------*/
#ifndef V4L2_CAPTURE
#define V4L2_CAPTURE
#include <string>
#include <list>
#include <iostream>
// ---------------------------------
// V4L2 Capture parameters
// ---------------------------------
struct V4L2DeviceParameters
{
V4L2DeviceParameters(const char* devname, unsigned int format, unsigned int width, unsigned int height, int fps, int verbose) :
m_devName(devname), m_format(format), m_width(width), m_height(height), m_fps(fps), m_verbose(verbose) {};
std::string m_devName;
unsigned int m_format;
unsigned int m_width;
unsigned int m_height;
int m_fps;
int m_verbose;
};
// ---------------------------------
// V4L2 Capture
// ---------------------------------
class V4l2Capture
{
protected:
V4l2Capture(V4L2DeviceParameters params);
public:
virtual ~V4l2Capture();
public:
int getFd() { return m_fd; };
int getBufferSize() { return m_bufferSize; };
int getFormat() { return m_format; } ;
void queryFormat();
protected:
bool init(unsigned int mandatoryCapabilities);
void close();
int initdevice(const char *dev_name, unsigned int mandatoryCapabilities);
int checkCapabilities(int fd, unsigned int mandatoryCapabilities);
int configureFormat(int fd);
int configureParam(int fd);
int xioctl(int fd, int request, void *arg);
public:
virtual bool captureStart() = 0;
virtual size_t read(char* buffer, size_t bufferSize) = 0;
virtual bool captureStop() = 0;
virtual bool isReady() = 0;
protected:
V4L2DeviceParameters m_params;
int m_fd;
int m_bufferSize;
int m_format;
};
#endif

@ -1,46 +0,0 @@
/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** V4l2MmapCapture.h
**
** V4L2 source using mmap API
**
** -------------------------------------------------------------------------*/
#ifndef V4L2_MMAP_CAPTURE
#define V4L2_MMAP_CAPTURE
// project
#include "V4l2Capture.h"
#define V4L2MMAP_NBBUFFER 10
class V4l2MmapCapture : public V4l2Capture
{
public:
static V4l2MmapCapture* createNew(V4L2DeviceParameters params);
protected:
V4l2MmapCapture(V4L2DeviceParameters params) : V4l2Capture(params), n_buffers(0) {};
public:
virtual bool captureStart();
virtual size_t read(char* buffer, size_t bufferSize);
virtual bool captureStop();
virtual bool isReady() { return ((m_fd != -1)&& (n_buffers != 0)); };
protected:
unsigned int n_buffers;
struct buffer
{
void * start;
size_t length;
};
buffer m_buffer[V4L2MMAP_NBBUFFER];
};
#endif

@ -1,37 +0,0 @@
/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** V4l2ReadCapture.h
**
** V4L2 source using read API
**
** -------------------------------------------------------------------------*/
#ifndef V4L2_READ_CAPTURE
#define V4L2_READ_CAPTURE
// project
#include "V4l2Capture.h"
class V4l2ReadCapture : public V4l2Capture
{
public:
static V4l2ReadCapture* createNew(V4L2DeviceParameters params);
protected:
V4l2ReadCapture(V4L2DeviceParameters params) : V4l2Capture(params), m_counter(0) {};
public:
virtual bool captureStart() { m_counter=1; return true; };
virtual size_t read(char* buffer, size_t bufferSize);
virtual bool captureStop() { m_counter=0; return true; };
virtual bool isReady() { return ((m_fd != -1) && (m_counter>0)); };
protected:
int m_counter;
};
#endif

@ -1,196 +0,0 @@
/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** V4l2Capture.cpp
**
** V4L2 wrapper
**
** -------------------------------------------------------------------------*/
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <iomanip>
#include <sstream>
#include <sys/ioctl.h>
// libv4l2
#include <linux/videodev2.h>
#include <libv4l2.h>
// project
#include "V4l2Capture.h"
// Constructor
V4l2Capture::V4l2Capture(V4L2DeviceParameters params) : m_params(params), m_fd(-1), m_bufferSize(0), m_format(0)
{
}
// Destructor
V4l2Capture::~V4l2Capture()
{
if (m_fd !=-1) v4l2_close(m_fd);
}
// intialize the V4L2 connection
bool V4l2Capture::init(unsigned int mandatoryCapabilities)
{
if (initdevice(m_params.m_devName.c_str(), mandatoryCapabilities) == -1)
{
fprintf(stderr, "[%s] Init device:%s failure\n", __FILE__, m_params.m_devName.c_str());
}
return (m_fd!=-1);
}
// close the V4L2 connection
void V4l2Capture::close()
{
if (m_fd != -1) v4l2_close(m_fd);
m_fd = -1;
}
// intialize the V4L2 device
int V4l2Capture::initdevice(const char *dev_name, unsigned int mandatoryCapabilities)
{
m_fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
if (m_fd < 0)
{
perror("Cannot open device");
this->close();
return -1;
}
if (checkCapabilities(m_fd,mandatoryCapabilities) !=0)
{
this->close();
return -1;
}
if (configureFormat(m_fd) !=0)
{
this->close();
return -1;
}
if (configureParam(m_fd) !=0)
{
this->close();
return -1;
}
return m_fd;
}
// check needed V4L2 capabilities
int V4l2Capture::checkCapabilities(int fd, unsigned int mandatoryCapabilities)
{
struct v4l2_capability cap;
memset(&(cap), 0, sizeof(cap));
if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap))
{
fprintf(stderr, "[%s] xioctl cannot get capabilities error %d, %s\n", __FILE__, errno, strerror(errno));
return -1;
}
fprintf(stderr, "driver:%s capabilities;%X\n", cap.driver, cap.capabilities);
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
{
fprintf(stderr, "[%s] the device '%s' doesnot support capture\n", __FILE__, m_params.m_devName.c_str());
return -1;
}
if ((cap.capabilities & V4L2_CAP_READWRITE)) fprintf(stderr, "%s support read i/o\n", m_params.m_devName.c_str());
if ((cap.capabilities & V4L2_CAP_STREAMING)) fprintf(stderr, "%s support streaming i/o\n", m_params.m_devName.c_str());
if ((cap.capabilities & V4L2_CAP_TIMEPERFRAME)) fprintf(stderr, "%s support timeperframe\n", m_params.m_devName.c_str());
if ( (cap.capabilities & mandatoryCapabilities) != mandatoryCapabilities )
{
fprintf(stderr, "%s mandatory capabilities not available\n", m_params.m_devName.c_str());
return -1;
}
return 0;
}
// configure capture format
int V4l2Capture::configureFormat(int fd)
{
struct v4l2_format fmt;
memset(&(fmt), 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = m_params.m_width;
fmt.fmt.pix.height = m_params.m_height;
fmt.fmt.pix.pixelformat = m_params.m_format;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
{
fprintf(stderr, "Cannot set format error %d, %s\n", errno, strerror(errno));
return -1;
}
if (fmt.fmt.pix.pixelformat != m_params.m_format)
{
printf("Error: format (%d) refused.\n", m_params.m_format);
return -1;
}
if ((fmt.fmt.pix.width != m_params.m_width) || (fmt.fmt.pix.height != m_params.m_height))
{
printf("Warning: driver is sending image at %dx%d\n", fmt.fmt.pix.width, fmt.fmt.pix.width);
}
m_format = fmt.fmt.pix.pixelformat;
m_bufferSize = fmt.fmt.pix.sizeimage;
fprintf(stderr, "[%s] bufferSize:%d\n", __FILE__, m_bufferSize);
return 0;
}
// configure capture FPS
int V4l2Capture::configureParam(int fd)
{
struct v4l2_streamparm param;
memset(&(param), 0, sizeof(param));
param.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
param.parm.capture.timeperframe.numerator = 1;
param.parm.capture.timeperframe.denominator = m_params.m_fps;
if (xioctl(fd, VIDIOC_S_PARM, &param) == -1)
{
fprintf(stderr, "xioctl cannot set param error %d, %s\n", errno, strerror(errno));
return -1;
}
fprintf(stderr, "fps :%d/%d nbBuffer:%d\n", param.parm.capture.timeperframe.numerator, param.parm.capture.timeperframe.denominator, param.parm.capture.readbuffers);
return 0;
}
// query current format
void V4l2Capture::queryFormat()
{
struct v4l2_format fmt;
memset(&fmt,0,sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (0 == ioctl(m_fd,VIDIOC_G_FMT,&fmt)) // don't understand why xioctl give a different result
{
m_format = fmt.fmt.pix.pixelformat;
m_bufferSize = fmt.fmt.pix.sizeimage;
}
}
// ioctl encapsulation
int V4l2Capture::xioctl(int fd, int request, void *arg)
{
int ret = -1;
errno=0;
do
{
ret = v4l2_ioctl(fd, request, arg);
} while ((ret == -1) && ((errno == EINTR) || (errno == EAGAIN)));
return ret;
}

@ -1,192 +0,0 @@
/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** V4l2MmapCapture.cpp
**
** V4L2 source using mmap API
**
** -------------------------------------------------------------------------*/
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/mman.h>
// libv4l2
#include <linux/videodev2.h>
#include <libv4l2.h>
// project
#include "V4l2MmapCapture.h"
V4l2MmapCapture* V4l2MmapCapture::createNew(V4L2DeviceParameters params)
{
V4l2MmapCapture* device = new V4l2MmapCapture(params);
if (device && !device->init(V4L2_CAP_STREAMING))
{
delete device;
device=NULL;
}
return device;
}
bool V4l2MmapCapture::captureStart()
{
bool success = true;
struct v4l2_requestbuffers req;
memset (&req, 0, sizeof(req));
req.count = V4L2MMAP_NBBUFFER;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(m_fd, VIDIOC_REQBUFS, &req))
{
if (EINVAL == errno)
{
fprintf(stderr, "%s does not support memory mapping\n", m_params.m_devName.c_str());
success = false;
}
else
{
perror("VIDIOC_REQBUFS");
success = false;
}
}
else
{
fprintf(stderr, "%s memory mapping nb buffer:%d\n", m_params.m_devName.c_str(), req.count);
// allocate buffers
memset(&m_buffer,0, sizeof(m_buffer));
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
struct v4l2_buffer buf;
memset (&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if (-1 == xioctl(m_fd, VIDIOC_QUERYBUF, &buf))
{
perror("VIDIOC_QUERYBUF");
success = false;
}
else
{
fprintf(stderr, "%s memory mapping buffer:%d size:%d\n", m_params.m_devName.c_str(), n_buffers, buf.length);
m_buffer[n_buffers].length = buf.length;
m_buffer[n_buffers].start = mmap ( NULL /* start anywhere */,
buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
m_fd,
buf.m.offset);
if (MAP_FAILED == m_buffer[n_buffers].start)
{
perror("mmap");
success = false;
}
}
}
// queue buffers
for (unsigned int i = 0; i < n_buffers; ++i)
{
struct v4l2_buffer buf;
memset (&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == xioctl(m_fd, VIDIOC_QBUF, &buf))
{
perror("VIDIOC_QBUF");
success = false;
}
}
// start stream
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(m_fd, VIDIOC_STREAMON, &type))
{
perror("VIDIOC_STREAMON");
success = false;
}
}
return success;
}
size_t V4l2MmapCapture::read(char* buffer, size_t bufferSize)
{
size_t size = 0;
if (n_buffers > 0)
{
struct v4l2_buffer buf;
memset (&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(m_fd, VIDIOC_DQBUF, &buf))
{
perror("VIDIOC_DQBUF");
size = -1;
}
else if (buf.index < n_buffers)
{
size = buf.bytesused;
if (size > bufferSize)
{
size = bufferSize;
fprintf(stderr, "%s buffer truncated:%d size:%d\n", m_params.m_devName.c_str(), m_buffer[buf.index].length, bufferSize);
}
memcpy(buffer, m_buffer[buf.index].start, size);
if (-1 == xioctl(m_fd, VIDIOC_QBUF, &buf))
{
perror("VIDIOC_QBUF");
size = -1;
}
}
}
return size;
}
bool V4l2MmapCapture::captureStop()
{
bool success = true;
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(m_fd, VIDIOC_STREAMOFF, &type))
{
perror("VIDIOC_STREAMOFF");
success = false;
}
for (unsigned int i = 0; i < n_buffers; ++i)
{
if (-1 == munmap (m_buffer[i].start, m_buffer[i].length))
{
perror("munmap");
success = false;
}
}
// free buffers
struct v4l2_requestbuffers req;
memset (&req, 0, sizeof(req));
req.count = 0;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(m_fd, VIDIOC_REQBUFS, &req))
{
perror("VIDIOC_REQBUFS");
success = false;
}
n_buffers = 0;
return success;
}

@ -1,37 +0,0 @@
/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** V4l2ReadCapture.cpp
**
** V4L2 source using read API
**
** -------------------------------------------------------------------------*/
// libv4l2
#include <linux/videodev2.h>
#include <libv4l2.h>
// project
#include "V4l2ReadCapture.h"
// Creator
V4l2ReadCapture* V4l2ReadCapture::createNew(V4L2DeviceParameters params)
{
V4l2ReadCapture* device = new V4l2ReadCapture(params);
if (device && !device->init(V4L2_CAP_READWRITE))
{
delete device;
device=NULL;
}
return device;
}
size_t V4l2ReadCapture::read(char* buffer, size_t bufferSize)
{
return v4l2_read(m_fd, buffer, bufferSize);
}

@ -0,0 +1 @@
Subproject commit 3582a9c9da4bd75a8347d4b09defd6babc008f6d
Loading…
Cancel
Save