changed to a more OO style interface; dequeueBuffer() still blocks indefinitely

git-svn-id: svn://anubis/misc/WebcamTracker@124 bd8a9e45-a331-0410-811e-c64571078777
This commit is contained in:
josh 2009-08-08 04:36:25 +00:00
parent 5a72b568b9
commit 3f048de88d
2 changed files with 211 additions and 136 deletions

View File

@ -14,33 +14,70 @@ using namespace std;
int main(int argc, char * argv[]) int main(int argc, char * argv[])
{ {
WebcamTracker("/dev/video0"); WebcamTracker wt;
wt.open("/dev/video0");
wt.start();
} }
WebcamTracker::WebcamTracker(const char * device) WebcamTracker::WebcamTracker()
{ {
m_open = false; m_open = false;
m_fd = open(device, O_RDWR); m_buffers = NULL;
m_lengths = NULL;
}
bool WebcamTracker::open(const char * device)
{
m_fd = ::open(device, O_RDWR);
if (m_fd >= 0) if (m_fd >= 0)
{ {
m_open = true;
struct v4l2_capability cap; struct v4l2_capability cap;
int ret = ioctl(m_fd, VIDIOC_QUERYCAP, &cap); int ret = ioctl(m_fd, VIDIOC_QUERYCAP, &cap);
if (ret != 0) if (ret != 0)
{ {
cerr << "VIDIOC_QUERYCAP ioctl failed: " << ret << endl; perror("VIDIOC_QUERYCAP");
} }
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) else
{
if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
{
m_open = true;
}
else
{ {
cerr << "Warning: V4L2_CAP_VIDEO_CAPTURE not supported!" << endl; cerr << "Warning: V4L2_CAP_VIDEO_CAPTURE not supported!" << endl;
} }
}
}
else
{
cerr << "Could not open device '" << device << "'" << endl;
}
return m_open;
}
void WebcamTracker::start()
{
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; v4l2_requestbuffers reqbuf;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.count = 1; reqbuf.count = num;
reqbuf.memory = V4L2_MEMORY_MMAP; reqbuf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(m_fd, VIDIOC_REQBUFS, &reqbuf); int ret = ioctl(m_fd, VIDIOC_REQBUFS, &reqbuf);
if (ret != 0) if (ret != 0)
{ {
cerr << "VIDIOC_REQBUFS ioctl failed: returned " << ret cerr << "VIDIOC_REQBUFS ioctl failed: returned " << ret
@ -51,11 +88,21 @@ WebcamTracker::WebcamTracker(const char * device)
cerr << " (EINVAL)"; cerr << " (EINVAL)";
cerr << endl; cerr << endl;
} }
else
{
m_numbufs = reqbuf.count;
cout << "Got " << m_numbufs << " buffers" << endl;
m_buffers = new void *[m_numbufs];
m_lengths = new int[m_numbufs];
}
}
void WebcamTracker::mapBuffer(int i)
{
struct v4l2_buffer buf; struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.index = 0; buf.index = i;
ret = ioctl(m_fd, VIDIOC_QUERYBUF, &buf); int ret = ioctl(m_fd, VIDIOC_QUERYBUF, &buf);
if (ret != 0) if (ret != 0)
{ {
cerr << "VIDIOC_QUERYBUF ioctl failed: returned " << ret cerr << "VIDIOC_QUERYBUF ioctl failed: returned " << ret
@ -65,10 +112,10 @@ WebcamTracker::WebcamTracker(const char * device)
cerr << endl; cerr << endl;
} }
m_vidbuflen = buf.length; m_buffers[i] = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
m_vidbuf = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, MAP_SHARED, m_fd, buf.m.offset);
m_fd, buf.m.offset); m_lengths[i] = buf.length;
if (m_vidbuf == MAP_FAILED) if (m_buffers[i] == MAP_FAILED)
{ {
cerr << "mmap() failed: errno " << errno; cerr << "mmap() failed: errno " << errno;
if (errno == EBADF) if (errno == EBADF)
@ -81,12 +128,15 @@ WebcamTracker::WebcamTracker(const char * device)
cerr << " (ENOMEM)"; cerr << " (ENOMEM)";
cerr << endl; cerr << endl;
} }
}
void WebcamTracker::queueBuffer(int i)
{
v4l2_buffer qbuf; v4l2_buffer qbuf;
qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
qbuf.memory = V4L2_MEMORY_MMAP; qbuf.memory = V4L2_MEMORY_MMAP;
qbuf.index = 0; qbuf.index = i;
ret = ioctl(m_fd, VIDIOC_QBUF, &qbuf); int ret = ioctl(m_fd, VIDIOC_QBUF, &qbuf);
if (ret != 0) if (ret != 0)
{ {
cerr << "VIDIOC_QBUF failed! errno = " << errno; cerr << "VIDIOC_QBUF failed! errno = " << errno;
@ -100,9 +150,12 @@ WebcamTracker::WebcamTracker(const char * device)
cerr << " (EIO)"; cerr << " (EIO)";
cerr << endl; cerr << endl;
} }
}
void WebcamTracker::beginStreaming()
{
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(m_fd, VIDIOC_STREAMON, &type); int ret = ioctl(m_fd, VIDIOC_STREAMON, &type);
if (ret != 0) if (ret != 0)
{ {
cerr << "VIDIOC_STREAMON ioctl failed! errno = " << errno; cerr << "VIDIOC_STREAMON ioctl failed! errno = " << errno;
@ -110,28 +163,26 @@ WebcamTracker::WebcamTracker(const char * device)
cerr << " (EINVAL)"; cerr << " (EINVAL)";
cerr << endl; cerr << endl;
} }
}
struct v4l2_buffer querybuf; void WebcamTracker::endStreaming()
querybuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; {
querybuf.index = 0; int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(m_fd, VIDIOC_QUERYBUF, &querybuf); int ret = ioctl(m_fd, VIDIOC_STREAMOFF, &type);
if (ret != 0) if (ret != 0)
{ {
cerr << "VIDIOC_QUERYBUF ioctl failed: returned " << ret cerr << "VIDIOC_STREAMOFF ioctl failed! errno = " << errno;
<< ", errno: " << errno;
if (errno == EINVAL) if (errno == EINVAL)
cerr << " (EINVAL)"; cerr << " (EINVAL)";
cerr << endl; cerr << endl;
} }
if (querybuf.flags & V4L2_BUF_FLAG_DONE) }
{
cout << "buf done" << endl;
}
v4l2_buffer dqbuf; void WebcamTracker::dequeueBuffer(v4l2_buffer * dqbuf)
dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; {
dqbuf.memory = V4L2_MEMORY_MMAP; dqbuf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(m_fd, VIDIOC_DQBUF, &dqbuf); dqbuf->memory = V4L2_MEMORY_MMAP;
int ret = ioctl(m_fd, VIDIOC_DQBUF, dqbuf);
if (ret != 0) if (ret != 0)
{ {
cerr << "VIDIOC_DQBUF failed! errno = " << errno; cerr << "VIDIOC_DQBUF failed! errno = " << errno;
@ -145,20 +196,15 @@ WebcamTracker::WebcamTracker(const char * device)
cerr << " (EIO)"; cerr << " (EIO)";
cerr << endl; cerr << endl;
} }
}
else
{
cerr << "Could not open device '" << device << "'" << endl;
}
} }
WebcamTracker::~WebcamTracker() void WebcamTracker::unmapBuffer(int i)
{ {
if (m_open) munmap(m_buffers[i], m_lengths[i]);
{ }
munmap(m_vidbuf, m_vidbuflen);
void WebcamTracker::freeBuffers()
{
v4l2_requestbuffers reqbuf; v4l2_requestbuffers reqbuf;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.count = 0; reqbuf.count = 0;
@ -173,6 +219,22 @@ WebcamTracker::~WebcamTracker()
if (errno == EINVAL) if (errno == EINVAL)
cerr << "EINVAL" << endl; 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); close(m_fd);
} }
} }

View File

@ -6,16 +6,29 @@
#include <sys/ioctl.h> /* ioctl() */ #include <sys/ioctl.h> /* ioctl() */
#include <libv4lconvert.h> #include <libv4lconvert.h>
#include <iostream> #include <iostream>
#include <vector>
class WebcamTracker class WebcamTracker
{ {
public: public:
WebcamTracker(const char * device); WebcamTracker();
~WebcamTracker(); ~WebcamTracker();
bool open(const char * device);
void start();
protected: protected:
void * m_vidbuf; void requestBuffers(int num);
int m_vidbuflen; void mapBuffer(int i);
void queueBuffer(int i);
void beginStreaming();
void endStreaming();
void dequeueBuffer(v4l2_buffer * dqbuf);
void unmapBuffer(int i);
void freeBuffers();
bool m_open; bool m_open;
int m_fd; int m_fd;
int m_numbufs;
void ** m_buffers;
int * m_lengths;
}; };