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 Playerstage-commit@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/playerstage-commit