WebcamTracker/WebcamTracker.cc
josh 7b70159842 added setFormat() to call ioctl VIDIOC_S_FMT and deallocating a buffer no longer blocks!!
git-svn-id: svn://anubis/misc/WebcamTracker@125 bd8a9e45-a331-0410-811e-c64571078777
2009-08-12 02:52:39 +00:00

269 lines
6.5 KiB
C++

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h> /* exit() */
#include <sys/ioctl.h> /* ioctl() */
#include <libv4lconvert.h>
#include <unistd.h>
#include <sys/mman.h> /* mmap() */
#include <errno.h>
#include <string.h> /* memset() */
#include <iostream>
#include "WebcamTracker.h"
using namespace std;
int main(int argc, char * argv[])
{
WebcamTracker wt;
wt.open("/dev/video0");
wt.start();
}
WebcamTracker::WebcamTracker()
{
m_open = false;
m_buffers = NULL;
m_lengths = NULL;
}
bool WebcamTracker::open(const char * device)
{
m_fd = ::open(device, O_RDWR);
if (m_fd >= 0)
{
struct v4l2_capability cap;
int ret = ioctl(m_fd, VIDIOC_QUERYCAP, &cap);
if (ret != 0)
{
perror("VIDIOC_QUERYCAP");
}
else
{
if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
{
m_open = true;
}
else
{
cerr << "Warning: V4L2_CAP_VIDEO_CAPTURE not supported!" << endl;
}
}
}
else
{
cerr << "Could not open device '" << device << "'" << endl;
}
return m_open;
}
void WebcamTracker::start()
{
setFormat();
requestBuffers(20);
for (int i = 0; i < m_numbufs; i++)
{
mapBuffer(i);
queueBuffer(i);
}
beginStreaming();
v4l2_buffer buf;
dequeueBuffer(&buf);
endStreaming();
}
void WebcamTracker::requestBuffers(int num)
{
m_numbufs = 0;
v4l2_requestbuffers reqbuf;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.count = num;
reqbuf.memory = V4L2_MEMORY_MMAP;
int ret = ioctl(m_fd, VIDIOC_REQBUFS, &reqbuf);
if (ret != 0)
{
cerr << "VIDIOC_REQBUFS ioctl failed: returned " << ret
<< ", errno " << errno;
if (errno == EBUSY)
cerr << " (EBUSY)";
if (errno == EINVAL)
cerr << " (EINVAL)";
cerr << endl;
}
else
{
m_numbufs = reqbuf.count;
m_buffers = new void *[m_numbufs];
m_lengths = new int[m_numbufs];
}
}
void WebcamTracker::mapBuffer(int i)
{
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.index = i;
int ret = ioctl(m_fd, VIDIOC_QUERYBUF, &buf);
if (ret != 0)
{
cerr << "VIDIOC_QUERYBUF ioctl failed: returned " << ret
<< ", errno: " << errno;
if (errno == EINVAL)
cerr << " (EINVAL)";
cerr << endl;
}
m_buffers[i] = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED, m_fd, buf.m.offset);
m_lengths[i] = buf.length;
if (m_buffers[i] == MAP_FAILED)
{
cerr << "mmap() failed: errno " << errno;
if (errno == EBADF)
cerr << " (EBADF)";
if (errno == EACCES)
cerr << " (EACCES)";
if (errno == EINVAL)
cerr << " (EINVAL)";
if (errno == ENOMEM)
cerr << " (ENOMEM)";
cerr << endl;
}
}
void WebcamTracker::queueBuffer(int i)
{
v4l2_buffer qbuf;
qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
qbuf.memory = V4L2_MEMORY_MMAP;
qbuf.index = i;
int ret = ioctl(m_fd, VIDIOC_QBUF, &qbuf);
if (ret != 0)
{
cerr << "VIDIOC_QBUF failed! errno = " << errno;
if (errno == EAGAIN)
cerr << " (EAGAIN)";
if (errno == EINVAL)
cerr << " (EINVAL)";
if (errno == ENOMEM)
cerr << " (ENOMEM)";
if (errno == EIO)
cerr << " (EIO)";
cerr << endl;
}
}
void WebcamTracker::beginStreaming()
{
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int ret = ioctl(m_fd, VIDIOC_STREAMON, &type);
if (ret != 0)
{
cerr << "VIDIOC_STREAMON ioctl failed! errno = " << errno;
if (errno == EINVAL)
cerr << " (EINVAL)";
cerr << endl;
}
}
void WebcamTracker::endStreaming()
{
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int ret = ioctl(m_fd, VIDIOC_STREAMOFF, &type);
if (ret != 0)
{
cerr << "VIDIOC_STREAMOFF ioctl failed! errno = " << errno;
if (errno == EINVAL)
cerr << " (EINVAL)";
cerr << endl;
}
}
void WebcamTracker::dequeueBuffer(v4l2_buffer * dqbuf)
{
dqbuf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
dqbuf->memory = V4L2_MEMORY_MMAP;
int ret = ioctl(m_fd, VIDIOC_DQBUF, dqbuf);
if (ret != 0)
{
cerr << "VIDIOC_DQBUF failed! errno = " << errno;
if (errno == EAGAIN)
cerr << " (EAGAIN)";
if (errno == EINVAL)
cerr << " (EINVAL)";
if (errno == ENOMEM)
cerr << " (ENOMEM)";
if (errno == EIO)
cerr << " (EIO)";
cerr << endl;
}
}
void WebcamTracker::unmapBuffer(int i)
{
munmap(m_buffers[i], m_lengths[i]);
}
void WebcamTracker::freeBuffers()
{
v4l2_requestbuffers reqbuf;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.count = 0;
reqbuf.memory = V4L2_MEMORY_MMAP;
int ret = ioctl(m_fd, VIDIOC_REQBUFS, &reqbuf);
if (ret != 0)
{
cerr << "~WebcamTracker(): VIDIOC_REQBUFS ioctl failed: "
<< ret << endl;
if (errno == EBUSY)
cerr << "EBUSY" << endl;
if (errno == EINVAL)
cerr << "EINVAL" << endl;
}
}
WebcamTracker::~WebcamTracker()
{
if (m_open)
{
if (m_buffers)
{
for (int i = 0; i < m_numbufs; i++)
{
unmapBuffer(i);
}
delete m_buffers;
delete m_lengths;
freeBuffers();
}
close(m_fd);
}
}
void WebcamTracker::setFormat()
{
v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int ret = ioctl(m_fd, VIDIOC_G_FMT, &fmt);
if (ret != 0)
{
cerr << "Warning: VIDIOC_G_FMT ioctl failed, errno " << errno;
if (errno == EBUSY)
cerr << " (EBUSY)";
if (errno == EINVAL)
cerr << " (EINVAL)";
cerr << endl;
}
cerr << "width: " << fmt.fmt.pix.width << endl;
cerr << "height: " << fmt.fmt.pix.height << endl;
cerr << "pixelformat: " << fmt.fmt.pix.pixelformat << endl;
cerr << "field: " << fmt.fmt.pix.field << endl;
cerr << "bytesperline: " << fmt.fmt.pix.bytesperline << endl;
ret = ioctl(m_fd, VIDIOC_S_FMT, &fmt);
if (ret != 0)
{
cerr << "Warning: VIDIOC_S_FMT ioctl failed, errno " << errno << endl;
}
}