00001 #include <cstdio>
00002 #include <iostream>
00003 #include <iomanip>
00004 #include <unistd.h>
00005 #include <sys/mman.h>
00006
00007 #include "camera.h"
00008
00009
00010 v4l_capture::v4l_capture()
00011 : dev_name(""), fd(-1), width(640), height(480),
00012 buffers(NULL), n_buffers(0)
00013 {};
00014
00015 v4l_capture::~v4l_capture()
00016 {
00017 stop_capturing();
00018 uninit_device();
00019 close_device();
00020 };
00021
00022 int
00023 v4l_capture::init(size_t _width, size_t _height, unsigned int devId)
00024 {
00025 width = _width;
00026 height = _height;
00027 if (!init_all(width, height, devId)) return -1;
00028 frame = cv::Mat(height, width, CV_8UC3);
00029 return 0;
00030 }
00031
00032 uchar *
00033 v4l_capture::capture ()
00034 {
00035 if (!write_img(frame.data)) return NULL;
00036 return frame.data;
00037 }
00038
00039
00040 int v4l_capture::getWidth ()
00041 {
00042 return width;
00043 }
00044
00045 int v4l_capture::getHeight ()
00046 {
00047 return height;
00048 }
00049
00050 bool v4l_capture::init_all(size_t _width, size_t _height, unsigned int _devId)
00051 {
00052 width = _width;
00053 height = _height;
00054 std::ostringstream oss("");
00055 oss << "/dev/video" << _devId;
00056 dev_name = oss.str();
00057 if (!open_device()) return false;
00058 init_device();
00059 if (!start_capturing()) return false;
00060 return true;
00061 }
00062
00063 bool v4l_capture::open_device(void)
00064 {
00065 fprintf(stderr, "Opening device '%s'\n", dev_name.c_str());
00066 fd = open(dev_name.c_str(), O_RDWR, 0);
00067
00068 if (fd == -1) {
00069 fprintf(stderr, "Cannot open '%s': %d, %s\n",
00070 dev_name.c_str(), errno, strerror(errno));
00071 return false;
00072 }
00073 return true;
00074 }
00075
00076 bool v4l_capture::close_device(void)
00077 {
00078 if (close(fd) == -1) {
00079 perror("close");
00080 return false;
00081 }
00082 fd = -1;
00083 return true;
00084 }
00085
00086 bool v4l_capture::write_img(uchar* ret)
00087 {
00088 if (!read_frame()) return false;
00089
00090 for (int i = 0; i < width * height; i += 2) {
00091 int y, r, g, b;
00092 int u, v;
00093 y = ((unsigned char *) buffers[0].start)[i * 2];
00094 u = ((unsigned char *) buffers[0].start)[i * 2 + 1] - 128;
00095 v = ((unsigned char *) buffers[0].start)[i * 2 + 3] - 128;
00096
00097 r = y + 1.40200 * v;
00098 g = y - 0.71414 * v - 0.34414 * u;
00099 b = y + 1.77200 * u;
00100 ret[i * 3 + 0] = (unsigned char) (std::min(std::max(r, 0), 255));
00101 ret[i * 3 + 1] = (unsigned char) (std::min(std::max(g, 0), 255));
00102 ret[i * 3 + 2] = (unsigned char) (std::min(std::max(b, 0), 255));
00103
00104 y = ((unsigned char *) buffers[0].start)[(i + 1) * 2];
00105
00106 r = y + 1.40200 * v;
00107 g = y - 0.71414 * v - 0.34414 * u;
00108 b = y + 1.77200 * u;
00109 ret[(i + 1) * 3 + 0] = (unsigned char) (std::min(std::max(r, 0), 255));
00110 ret[(i + 1) * 3 + 1] = (unsigned char) (std::min(std::max(g, 0), 255));
00111 ret[(i + 1) * 3 + 2] = (unsigned char) (std::min(std::max(b, 0), 255));
00112 }
00113
00114 return true;
00115 }
00116
00117 bool v4l_capture::read_frame(void)
00118 {
00119 struct v4l2_buffer buf;
00120
00121 memset (&(buf), 0, sizeof (buf));
00122
00123 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00124 buf.memory = V4L2_MEMORY_MMAP;
00125
00126 if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) {
00127 perror("VIDIOC_DQBUF");
00128 return false;
00129 }
00130 assert(buf.index < n_buffers);
00131
00132 if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
00133 perror("VIDIOC_QBUF");
00134 return false;
00135 }
00136
00137 return true;
00138 }
00139
00140 bool v4l_capture::init_mmap(void)
00141 {
00142 struct v4l2_requestbuffers req;
00143
00144 memset (&(req), 0, sizeof (req));
00145
00146 req.count = 4;
00147 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00148 req.memory = V4L2_MEMORY_MMAP;
00149
00150 if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
00151 perror("VIDIOC_REQBUFS");
00152 return false;
00153 }
00154
00155 if (req.count < 2) {
00156 fprintf(stderr, "Insufficient buffer memory on %s\n", dev_name.c_str());
00157 return false;
00158 }
00159
00160 buffers = (buffer*)calloc(req.count, sizeof(*buffers));
00161
00162 if (!buffers) {
00163 fprintf(stderr, "Out of memory\n");
00164 return false;
00165 }
00166
00167 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
00168 struct v4l2_buffer buf;
00169
00170 memset (&(buf), 0, sizeof (buf));
00171
00172 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00173 buf.memory = V4L2_MEMORY_MMAP;
00174 buf.index = n_buffers;
00175
00176 if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
00177 perror("VIDIOC_QUERYBUF");
00178 return false;
00179 }
00180
00181 buffers[n_buffers].length = buf.length;
00182 buffers[n_buffers].start = mmap(NULL ,
00183 buf.length, PROT_READ | PROT_WRITE
00184 ,
00185 MAP_SHARED ,
00186 fd, buf.m.offset);
00187
00188 if (buffers[n_buffers].start == MAP_FAILED) {
00189 perror("mmap");
00190 return false;
00191 }
00192 }
00193 return true;
00194 }
00195
00196 bool v4l_capture::uninit_mmap(void)
00197 {
00198 unsigned int i;
00199
00200 for (i = 0; i < n_buffers; ++i) {
00201 if (munmap(buffers[i].start, buffers[i].length) == -1) {
00202 perror("munmap");
00203 return false;
00204 }
00205 }
00206 return true;
00207 }
00208
00209 bool v4l_capture::init_device(void)
00210 {
00211 struct v4l2_capability cap;
00212 struct v4l2_format fmt;
00213
00214 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
00215 if (EINVAL == errno) {
00216 fprintf(stderr, "%s is no V4L2 device\n", dev_name.c_str());
00217 }
00218 perror("VIDIOC_QUERYCAP");
00219 return false;
00220 }
00221
00222 fprintf(stderr, "video capabilities\n");
00223 fprintf(stderr, "cap.driver = %s\n", cap.driver);
00224 fprintf(stderr, "cap.card = %s\n", cap.card);
00225 fprintf(stderr, "cap.buf_info = %s\n", cap.bus_info);
00226 fprintf(stderr, "cap.version = %d\n", cap.version);
00227 fprintf(stderr, "cap.capabilities = 0x%08x ", cap.capabilities);
00228 if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
00229 fprintf(stderr, " VIDEO_CAPTURE");
00230 if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
00231 fprintf(stderr, " VIDEO_OUTPUT");
00232 if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
00233 fprintf(stderr, " VIDEO_OVERLAY");
00234 if (cap.capabilities & V4L2_CAP_VBI_CAPTURE)
00235 fprintf(stderr, " VBI_CAPTURE");
00236 if (cap.capabilities & V4L2_CAP_VBI_OUTPUT)
00237 fprintf(stderr, " VBI_OUTPUT");
00238 #ifdef V4L2_CAP_SLICED_VBI_CAPTURE
00239 if (cap.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE)
00240 fprintf(stderr, " SLICED_VBI_CAPTURE");
00241 #endif
00242 #ifdef V4L2_CAP_SLICED_VBI_OUTPUT
00243 if (cap.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
00244 fprintf(stderr, " VBI_SLICED_OUTPUT");
00245 #endif
00246 if (cap.capabilities & V4L2_CAP_RDS_CAPTURE)
00247 fprintf(stderr, " RDS_CAPTURE");
00248 #if V4L2_CAP_VIDEO_OUTPUT_OVERLAY
00249 if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
00250 fprintf(stderr, " VIDEO_OUTPUT_OVERLAY");
00251 #endif
00252 if (cap.capabilities & V4L2_CAP_TUNER)
00253 fprintf(stderr, " TUNER");
00254 if (cap.capabilities & V4L2_CAP_AUDIO)
00255 fprintf(stderr, " AUDIO");
00256 if (cap.capabilities & V4L2_CAP_RADIO)
00257 fprintf(stderr, " RADIO");
00258 if (cap.capabilities & V4L2_CAP_READWRITE)
00259 fprintf(stderr, " READWRITE");
00260 if (cap.capabilities & V4L2_CAP_ASYNCIO)
00261 fprintf(stderr, " ASYNCIO");
00262 if (cap.capabilities & V4L2_CAP_STREAMING)
00263 fprintf(stderr, " STREAMING");
00264 fprintf(stderr, "\n");
00265
00266 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
00267 fprintf(stderr, "%s is no video capture device\n", dev_name.c_str());
00268 return false;
00269 }
00270
00271 memset (&(fmt), 0, sizeof (fmt));
00272
00273 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00274 fmt.fmt.pix.width = width;
00275 fmt.fmt.pix.height = height;
00276 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
00277 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
00278
00279 if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
00280 perror("VIDIOC_S_FMT");
00281 return false;
00282 }
00283
00284 init_mmap();
00285 return true;
00286 }
00287
00288 void v4l_capture::uninit_device(void)
00289 {
00290 uninit_mmap();
00291 free(buffers);
00292 }
00293
00294 bool v4l_capture::start_capturing(void)
00295 {
00296 unsigned int i;
00297 enum v4l2_buf_type type;
00298
00299 for (i = 0; i < n_buffers; ++i) {
00300 struct v4l2_buffer buf;
00301
00302 memset (&(buf), 0, sizeof (buf));
00303
00304 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00305 buf.memory = V4L2_MEMORY_MMAP;
00306 buf.index = i;
00307
00308 if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
00309 perror("VIDIOC_QBUF");
00310 return false;
00311 }
00312 }
00313
00314 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00315
00316 if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) {
00317 perror("VIDIOC_STREAMON");
00318 return false;
00319 }
00320 return true;
00321 }
00322
00323 bool v4l_capture::stop_capturing(void)
00324 {
00325 enum v4l2_buf_type type;
00326
00327 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00328
00329 if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) {
00330 perror("VIDIOC_STREAMOFF");
00331 return false;
00332 }
00333 return true;
00334 }