From 3f048de88da8417af3ea227ab9b4fbedac1489c5 Mon Sep 17 00:00:00 2001 From: josh Date: Sat, 8 Aug 2009 04:36:25 +0000 Subject: [PATCH] changed to a more OO style interface; dequeueBuffer() still blocks indefinitely git-svn-id: svn://anubis/misc/WebcamTracker@124 bd8a9e45-a331-0410-811e-c64571078777 --- WebcamTracker.cc | 328 ++++++++++++++++++++++++++++------------------- WebcamTracker.h | 19 ++- 2 files changed, 211 insertions(+), 136 deletions(-) diff --git a/WebcamTracker.cc b/WebcamTracker.cc index 0206d30..9329730 100644 --- a/WebcamTracker.cc +++ b/WebcamTracker.cc @@ -14,164 +14,226 @@ using namespace std; 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_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) { - m_open = true; - struct v4l2_capability cap; int ret = ioctl(m_fd, VIDIOC_QUERYCAP, &cap); if (ret != 0) { - cerr << "VIDIOC_QUERYCAP ioctl failed: " << ret << endl; + perror("VIDIOC_QUERYCAP"); } - if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) + else { - cerr << "Warning: V4L2_CAP_VIDEO_CAPTURE not supported!" << endl; + if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) + { + m_open = true; + } + else + { + cerr << "Warning: V4L2_CAP_VIDEO_CAPTURE not supported!" << endl; + } } - - v4l2_requestbuffers reqbuf; - reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - reqbuf.count = 1; - reqbuf.memory = V4L2_MEMORY_MMAP; - 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; - } - - struct v4l2_buffer buf; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.index = 0; - 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_vidbuflen = buf.length; - m_vidbuf = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, - m_fd, buf.m.offset); - if (m_vidbuf == 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; - } - - v4l2_buffer qbuf; - qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - qbuf.memory = V4L2_MEMORY_MMAP; - qbuf.index = 0; - 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; - } - - int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = ioctl(m_fd, VIDIOC_STREAMON, &type); - if (ret != 0) - { - cerr << "VIDIOC_STREAMON ioctl failed! errno = " << errno; - if (errno == EINVAL) - cerr << " (EINVAL)"; - cerr << endl; - } - - struct v4l2_buffer querybuf; - querybuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - querybuf.index = 0; - ret = ioctl(m_fd, VIDIOC_QUERYBUF, &querybuf); - if (ret != 0) - { - cerr << "VIDIOC_QUERYBUF ioctl failed: returned " << ret - << ", errno: " << errno; - if (errno == EINVAL) - cerr << " (EINVAL)"; - cerr << endl; - } - if (querybuf.flags & V4L2_BUF_FLAG_DONE) - { - cout << "buf done" << endl; - } - - v4l2_buffer dqbuf; - dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dqbuf.memory = V4L2_MEMORY_MMAP; - 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; - } - } 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; + 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; + 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; + 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) { - munmap(m_vidbuf, m_vidbuflen); - - 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) + if (m_buffers) { - cerr << "~WebcamTracker(): VIDIOC_REQBUFS ioctl failed: " - << ret << endl; - if (errno == EBUSY) - cerr << "EBUSY" << endl; - if (errno == EINVAL) - cerr << "EINVAL" << endl; + for (int i = 0; i < m_numbufs; i++) + { + unmapBuffer(i); + } + delete m_buffers; + delete m_lengths; + freeBuffers(); } close(m_fd); } diff --git a/WebcamTracker.h b/WebcamTracker.h index d7c5ad3..b19463f 100644 --- a/WebcamTracker.h +++ b/WebcamTracker.h @@ -6,16 +6,29 @@ #include /* ioctl() */ #include #include +#include class WebcamTracker { public: - WebcamTracker(const char * device); + WebcamTracker(); ~WebcamTracker(); + bool open(const char * device); + void start(); protected: - void * m_vidbuf; - int m_vidbuflen; + void requestBuffers(int num); + 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; int m_fd; + int m_numbufs; + void ** m_buffers; + int * m_lengths; };