Revision: 9090
http://playerstage.svn.sourceforge.net/playerstage/?rev=9090&view=rev
Author: jpgr87
Date: 2012-03-04 20:17:02 +0000 (Sun, 04 Mar 2012)
Log Message:
-----------
Applied patch #3496741: libv4l2 webcam driver for Player
Modified Paths:
--------------
code/player/trunk/server/drivers/camera/CMakeLists.txt
Added Paths:
-----------
code/player/trunk/server/drivers/camera/libv4l2/
code/player/trunk/server/drivers/camera/libv4l2/CMakeLists.txt
code/player/trunk/server/drivers/camera/libv4l2/libv4l2.cc
Modified: code/player/trunk/server/drivers/camera/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/camera/CMakeLists.txt 2012-03-04
20:12:30 UTC (rev 9089)
+++ code/player/trunk/server/drivers/camera/CMakeLists.txt 2012-03-04
20:17:02 UTC (rev 9090)
@@ -10,6 +10,7 @@
ADD_SUBDIRECTORY (imgcmp)
ADD_SUBDIRECTORY (imgsave)
ADD_SUBDIRECTORY (kinect)
+ADD_SUBDIRECTORY (libv4l2)
ADD_SUBDIRECTORY (powershot)
ADD_SUBDIRECTORY (sphere)
ADD_SUBDIRECTORY (uvc)
Added: code/player/trunk/server/drivers/camera/libv4l2/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/camera/libv4l2/CMakeLists.txt
(rev 0)
+++ code/player/trunk/server/drivers/camera/libv4l2/CMakeLists.txt
2012-03-04 20:17:02 UTC (rev 9090)
@@ -0,0 +1,14 @@
+PLAYERDRIVER_OPTION (libv4l2 build_libv4l2 ON)
+PLAYERDRIVER_REJECT_OS (libv4l2 build_libv4l2 PLAYER_OS_WIN)
+PLAYERDRIVER_REQUIRE_HEADER (libv4l2 build_libv4l2 linux/videodev2.h
sys/types.h)
+PLAYERDRIVER_REQUIRE_PKG (libv4l2 build_libv4l2 libv4l2 libv4l2_includeDirs
+ libv4l2_libDirs libv4l2_linkLibs libv4l2_linkFlags libv4l2_cFlags)
+PLAYERDRIVER_REQUIRE_PKG (libv4l2 build_libv4l2 libv4lconvert
libv4lconvert_includeDirs
+ libv4lconvert_libDirs libv4lconvert_linkLibs libv4lconvert_linkFlags
libv4lconvert_cFlags)
+PLAYERDRIVER_ADD_DRIVER (libv4l2 build_libv4l2
+ INCLUDEDIRS ${libv4l2_includeDirs} ${libv4lconvert_includeDirs}
+ LIBDIRS ${libv4l2_libDirs} ${libv4lconvert_libDirs}
+ LINKLIBS ${libv4l2_linkLibs} ${libv4lconvert_linkLibs}
+ LINKFLAGS ${libv4l2_linkFlags} ${libv4lconvert_linkFlags}
+ CFLAGS ${libv4l2_cFlags} ${libv4lconvert_cFlags}
+ SOURCES libv4l2.cc)
Added: code/player/trunk/server/drivers/camera/libv4l2/libv4l2.cc
===================================================================
--- code/player/trunk/server/drivers/camera/libv4l2/libv4l2.cc
(rev 0)
+++ code/player/trunk/server/drivers/camera/libv4l2/libv4l2.cc 2012-03-04
20:17:02 UTC (rev 9090)
@@ -0,0 +1,485 @@
+/*
+ * Player - One Hell of a Robot Server
+ * Copyright (C) 2000 Brian Gerkey et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+///////////////////////////////////////////////////////////////////////////
+//
+// Desc: libv4l2-based capture driver
+// Author: Paul Osmialowski
+// Date: 27 Feb 2012
+//
+///////////////////////////////////////////////////////////////////////////
+
+/** @ingroup drivers */
+/** @{ */
+/** @defgroup driver_libv4l2 libv4l2
+ * @brief libv4l2-based capture driver
+
+The libv4l2 driver captures images from various webcams.
+Based on v4l-utils (GNU GPL v2).
+
+@par Compile-time dependencies
+
+- libv4l2 (part of v4l-utils, shipped separately as media-libs/libv4l on
Gentoo Linux)
+
+@par Provides
+
+- @ref interface_camera
+
+@par Requires
+
+- none
+
+@par Configuration requests
+
+- none
+
+@par Configuration file options
+
+- port (string)
+ - Default: "/dev/video0"
+ - Device to read video data from.
+
+- sleep_nsec (integer)
+ - Default: 10000000 (=10ms which gives max 100 fps)
+ - timespec value for nanosleep()
+
+- request_only (integer)
+ - Default: 0
+ - If set to 1, data will be sent only at PLAYER_CAMEARA_REQ_GET_IMAGE
response.
+
+- read_mode (integer)
+ - Default: 0
+ - Set to 1 if read should be used instead of grab (in most cases it isn't a
good idea!)
+
+@par Example
+
+@verbatim
+driver
+(
+ name "libv4l2"
+ provides ["camera:0"]
+)
+@endverbatim
+
+@author Paul Osmialowski
+
+*/
+/** @} */
+
+#include <time.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <pthread.h>
+#include <libplayercore/playercore.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <linux/videodev2.h>
+#include <unistd.h>
+#include <libv4l2.h>
+#include <libv4lconvert.h>
+
+class Libv4l2 : public ThreadedDriver
+{
+public:
+ Libv4l2(ConfigFile * cf, int section);
+ virtual ~Libv4l2();
+
+ virtual int MainSetup();
+ virtual void MainQuit();
+ virtual int ProcessMessage(QueuePointer & resp_queue,
+ player_msghdr * hdr,
+ void * data);
+
+private:
+ virtual void Main();
+ void prepareData();
+ void cleanup();
+
+ static int instances;
+ player_devaddr_t camera_addr;
+ const char * port;
+ int sleep_nsec;
+ int request_only;
+ int read_mode;
+ int m_fd;
+ struct v4lconvert_data * convert;
+ struct v4l2_format srcfmt;
+ struct v4l2_format dstfmt;
+ struct buffer
+ {
+ void * start;
+ size_t length;
+ } * m_buffers;
+ size_t n_buffers;
+ int started;
+ player_camera_data_t * data;
+};
+
+int Libv4l2::instances = 0;
+
+Libv4l2::Libv4l2(ConfigFile * cf, int section)
+ : ThreadedDriver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN)
+{
+ assert(!(this->instances));
+ this->instances++;
+ memset(&(this->camera_addr), 0, sizeof(player_devaddr_t));
+ this->port = NULL;
+ this->sleep_nsec = 0;
+ this->request_only = 0;
+ this->read_mode = 0;
+ this->m_fd = -1;
+ this->convert = NULL;
+ memset(&(this->srcfmt), 0, sizeof this->srcfmt);
+ memset(&(this->dstfmt), 0, sizeof this->dstfmt);
+ this->m_buffers = NULL;
+ this->n_buffers = 0;
+ this->started = 0;
+ this->data = NULL;
+ if (cf->ReadDeviceAddr(&(this->camera_addr), section, "provides",
PLAYER_CAMERA_CODE, -1, NULL))
+ {
+ this->SetError(-1);
+ return;
+ }
+ if (this->AddInterface(this->camera_addr))
+ {
+ this->SetError(-1);
+ return;
+ }
+ this->port = cf->ReadString(section, "port", "/dev/video0");
+ if (!(this->port))
+ {
+ PLAYER_ERROR("Port not given");
+ this->SetError(-1);
+ return;
+ }
+ if (!(strlen(this->port) > 0))
+ {
+ PLAYER_ERROR("Empty port name");
+ this->SetError(-1);
+ return;
+ }
+ this->sleep_nsec = cf->ReadInt(section, "sleep_nsec", 10000000);
+ if ((this->sleep_nsec) < 0)
+ {
+ PLAYER_ERROR("Invalid sleep_nsec value");
+ this->SetError(-1);
+ return;
+ }
+ this->request_only = cf->ReadInt(section, "request_only", 0);
+ this->read_mode = cf->ReadInt(section, "read_mode", 0);
+}
+
+Libv4l2::~Libv4l2()
+{
+ this->cleanup();
+ assert(!(this->started));
+ assert((this->m_fd) < 0);
+ this->instances--;
+ assert(!(this->instances));
+}
+
+void Libv4l2::cleanup()
+{
+ int i;
+ struct v4l2_encoder_cmd cmd;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ struct v4l2_requestbuffers reqbuf;
+
+ if (this->data)
+ {
+ if (this->data->image) free(this->data->image);
+ this->data->image = NULL;
+ this->data->image_count = 0;
+ free(this->data);
+ }
+ this->data = NULL;
+ if (this->started)
+ {
+ assert(!((this->m_fd) < 0));
+ if (this->read_mode)
+ {
+ memset(&cmd, 0, sizeof cmd);
+ cmd.cmd = V4L2_ENC_CMD_STOP;
+ v4l2_ioctl(this->m_fd, VIDIOC_ENCODER_CMD, &cmd);
+ } else
+ {
+ v4l2_ioctl(this->m_fd, VIDIOC_STREAMOFF, &type);
+ }
+ }
+ this->started = 0;
+ if (this->m_buffers)
+ {
+ assert(!(this->read_mode));
+ assert(!((this->m_fd) < 0));
+ for (i = 0; i < static_cast<int>(this->n_buffers); i++)
+ {
+ if (this->m_buffers[i].start) v4l2_munmap(this->m_buffers[i].start,
this->m_buffers[i].length);
+ this->m_buffers[i].start = NULL;
+ }
+ memset(&reqbuf, 0, sizeof reqbuf);
+ reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ reqbuf.memory = V4L2_MEMORY_MMAP;
+ reqbuf.count = 1;
+ v4l2_ioctl(this->m_fd, VIDIOC_REQBUFS, &reqbuf);
+ memset(&reqbuf, 0, sizeof reqbuf);
+ reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ reqbuf.memory = V4L2_MEMORY_MMAP;
+ reqbuf.count = 0;
+ v4l2_ioctl(this->m_fd, VIDIOC_REQBUFS, &reqbuf);
+ free(this->m_buffers);
+ }
+ this->m_buffers = NULL;
+ this->n_buffers = 0;
+ if (this->convert) v4lconvert_destroy(this->convert);
+ this->convert = NULL;
+ if (!((this->m_fd) < 0)) v4l2_close(this->m_fd);
+ this->m_fd = -1;
+}
+
+int Libv4l2::MainSetup()
+{
+ assert(!(this->started));
+ assert((this->m_fd) < 0);
+ return 0;
+}
+
+void Libv4l2::MainQuit()
+{
+ this->cleanup();
+ assert(!(this->started));
+ assert((this->m_fd) < 0);
+}
+
+void Libv4l2::prepareData()
+{
+ ssize_t s;
+ unsigned char * frame = NULL;
+ struct v4l2_buffer buf;
+
+ assert(this->data);
+ if (this->data->image) free(this->data->image);
+ this->data->image = NULL;
+ this->data->image_count = 0;
+ s = 0;
+ if (this->read_mode)
+ {
+ assert((this->srcfmt.fmt.pix.sizeimage) > 0);
+ frame = reinterpret_cast<unsigned char
*>(malloc(this->srcfmt.fmt.pix.sizeimage));
+ assert(frame);
+ s = v4l2_read(this->m_fd, frame, this->srcfmt.fmt.pix.sizeimage);
+ if (!s)
+ {
+ PLAYER_ERROR("Cannot capture frame");
+ free(frame);
+ return;
+ }
+ if (s < 0)
+ {
+ free(frame);
+ return;
+ }
+ } else
+ {
+ memset(&buf, 0, sizeof buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ if (v4l2_ioctl(this->m_fd, VIDIOC_DQBUF, &buf) < 0) return;
+ s = buf.bytesused;
+ if (s <= 0)
+ {
+ PLAYER_ERROR("No data (or other error)");
+ return;
+ }
+ frame = reinterpret_cast<unsigned char *>(malloc(s));
+ assert(frame);
+ assert(this->m_buffers);
+ memcpy(frame, this->m_buffers[buf.index].start, s);
+ assert(v4l2_ioctl(this->m_fd, VIDIOC_QBUF, &buf) >= 0);
+ }
+ assert(s > 0);
+ assert(frame);
+ assert((this->dstfmt.fmt.pix.pixelformat) == V4L2_PIX_FMT_RGB24);
+ memset(this->data, 0, sizeof(player_camera_data_t));
+ this->data->width = this->dstfmt.fmt.pix.width;
+ this->data->height = this->dstfmt.fmt.pix.height;
+ this->data->bpp = 24;
+ this->data->format = PLAYER_CAMERA_FORMAT_RGB888;
+ this->data->fdiv = 0;
+ this->data->compression = PLAYER_CAMERA_COMPRESS_RAW;
+ this->data->image_count = s;
+ this->data->image = frame;
+}
+
+void Libv4l2::Main()
+{
+ struct v4l2_capability cap;
+ struct v4l2_fract interval;
+ struct v4l2_streamparm parm;
+ struct v4l2_requestbuffers req;
+ struct v4l2_buffer buf;
+ struct timespec ts;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ int interval_ok = 0;
+ int i;
+
+ assert(!(this->started));
+ assert(!(this->data));
+ assert(!(this->convert));
+ assert(!(this->m_buffers));
+ assert(!(this->n_buffers));
+ assert((this->m_fd) < 0);
+ this->m_fd = open(this->port, O_RDWR | O_NONBLOCK);
+ assert(!((this->m_fd) < 0));
+ memset(&cap, 0, sizeof cap);
+ assert(v4l2_ioctl(this->m_fd, VIDIOC_QUERYCAP, &cap) >= 0);
+ assert(v4l2_fd_open(this->m_fd, V4L2_ENABLE_ENUM_FMT_EMULATION) >= 0);
+ this->convert = v4lconvert_create(this->m_fd);
+ assert(this->convert);
+ memset(&(this->srcfmt), 0, sizeof this->srcfmt);
+ this->srcfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ assert(v4l2_ioctl(this->m_fd, VIDIOC_G_FMT, &(this->srcfmt)) >= 0);
+ if ((this->srcfmt.fmt.pix.pixelformat) != V4L2_PIX_FMT_RGB24)
+ {
+ memset(&interval, 0, sizeof interval);
+ memset(&parm, 0, sizeof parm);
+ parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ interval_ok = 0;
+ if (v4l2_ioctl(this->m_fd, VIDIOC_G_PARM, &parm) >= 0) if
(parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
+ {
+ interval = parm.parm.capture.timeperframe;
+ interval_ok = !0;
+ }
+ this->srcfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+ v4l2_ioctl(this->m_fd, VIDIOC_S_FMT, &(this->srcfmt)); /* ignore the
result! */
+ memset(&(this->srcfmt), 0, sizeof this->srcfmt);
+ this->srcfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ assert(v4l2_ioctl(this->m_fd, VIDIOC_G_FMT, &(this->srcfmt)) >= 0);
+ if (interval_ok)
+ {
+ memset(&parm, 0, sizeof parm);
+ parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (!(v4l2_ioctl(this->m_fd, VIDIOC_G_PARM, &parm) < 0)) if
(parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
+ {
+ parm.parm.capture.timeperframe = interval;
+ v4l2_ioctl(this->m_fd, VIDIOC_S_PARM, &parm); /* ignore the result! */
+ }
+ }
+ }
+ assert((this->srcfmt.fmt.pix.sizeimage) > 0);
+ memcpy(&(this->dstfmt), &(this->srcfmt), sizeof this->dstfmt);
+ this->dstfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+ if (!(this->read_mode))
+ {
+ memset(&req, 0, sizeof req);
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+ req.count = 3;
+ assert(v4l2_ioctl(this->m_fd, VIDIOC_REQBUFS, &req) >= 0);
+ assert((req.count) > 0);
+ this->m_buffers = reinterpret_cast<buffer *>(calloc(req.count,
sizeof(struct Libv4l2::buffer)));
+ assert(this->m_buffers);
+ this->n_buffers = req.count;
+ for (i = 0; i < static_cast<int>(this->n_buffers); i++)
+ {
+ memset(&buf, 0, sizeof buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+ assert(v4l2_ioctl(this->m_fd, VIDIOC_QUERYBUF, &buf) >= 0);
+ this->m_buffers[i].length = buf.length;
+ this->m_buffers[i].start = v4l2_mmap(NULL, this->m_buffers[i].length,
PROT_READ | PROT_WRITE, MAP_SHARED, this->m_fd, buf.m.offset);
+ assert(this->m_buffers[i].start != MAP_FAILED);
+ assert(this->m_buffers[i].start);
+ }
+ for (i = 0; i < static_cast<int>(this->n_buffers); i++)
+ {
+ memset(&buf, 0, sizeof buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+ assert(v4l2_ioctl(this->m_fd, VIDIOC_QBUF, &buf) >= 0);
+ }
+ assert(v4l2_ioctl(this->m_fd, VIDIOC_STREAMON, &type) >= 0);
+ }
+ this->started = !0;
+ this->data = reinterpret_cast<player_camera_data_t
*>(malloc(sizeof(player_camera_data_t)));
+ assert(this->data);
+ memset(this->data, 0, sizeof(player_camera_data_t));
+ this->data->image = NULL;
+ this->data->image_count = 0;
+ for (;;)
+ {
+ if ((this->sleep_nsec) > 0)
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = this->sleep_nsec;
+ nanosleep(&ts, NULL);
+ }
+ pthread_testcancel();
+ this->prepareData();
+ pthread_testcancel();
+ assert(this->data);
+ if (!(this->data->image)) continue;
+ assert((this->data->image_count) > 0);
+ if (!(this->request_only))
+ {
+ this->Publish(this->camera_addr,
+ PLAYER_MSGTYPE_DATA, PLAYER_CAMERA_DATA_STATE,
+ reinterpret_cast<void *>(this->data), 0, NULL, true);
+ // copy = true, we need to preserve the data
+ }
+ pthread_testcancel();
+ this->ProcessMessages();
+ pthread_testcancel();
+ }
+}
+
+int Libv4l2::ProcessMessage(QueuePointer & resp_queue, player_msghdr * hdr,
void * data)
+{
+ assert(hdr);
+ if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_CAMERA_REQ_GET_IMAGE, this->camera_addr))
+ {
+ if (!(this->started)) return -1;
+ if (!(this->data)) return -1;
+ if (!(this->data->image)) return -1;
+ if (!((this->data->image_count) > 0)) return -1;
+ this->Publish(this->camera_addr,
+ resp_queue,
+ PLAYER_MSGTYPE_RESP_ACK,
+ PLAYER_CAMERA_REQ_GET_IMAGE,
+ reinterpret_cast<void *>(this->data));
+ return 0;
+ }
+ return -1;
+}
+
+Driver * Libv4l2_Init(ConfigFile * cf, int section)
+{
+ return (Driver *)(new Libv4l2(cf, section));
+}
+
+void libv4l2_Register(DriverTable * table)
+{
+ table->AddDriver("libv4l2", Libv4l2_Init);
+}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Virtualization & Cloud Management Using Capacity Planning
Cloud computing makes use of virtualization - but cloud computing
also focuses on allowing computing to be delivered as a service.
http://www.accelacomm.com/jaw/sfnl/114/51521223/
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit