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 write_img(frame.data);
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 void v4l_capture::close_device(void)
00077 {
00078 if (close(fd) == -1) {
00079 perror("close");
00080 exit(EXIT_FAILURE);
00081 }
00082 fd = -1;
00083 }
00084
00085 void v4l_capture::write_img(uchar* ret)
00086 {
00087 read_frame();
00088
00089 for (int i = 0; i < width * height; i += 2) {
00090 int y, r, g, b;
00091 int u, v;
00092 y = ((unsigned char *) buffers[0].start)[i * 2];
00093 u = ((unsigned char *) buffers[0].start)[i * 2 + 1] - 128;
00094 v = ((unsigned char *) buffers[0].start)[i * 2 + 3] - 128;
00095
00096 r = y + 1.40200 * v;
00097 g = y - 0.71414 * v - 0.34414 * u;
00098 b = y + 1.77200 * u;
00099 ret[i * 3 + 0] = (unsigned char) (std::min(std::max(r, 0), 255));
00100 ret[i * 3 + 1] = (unsigned char) (std::min(std::max(g, 0), 255));
00101 ret[i * 3 + 2] = (unsigned char) (std::min(std::max(b, 0), 255));
00102
00103 y = ((unsigned char *) buffers[0].start)[(i + 1) * 2];
00104
00105 r = y + 1.40200 * v;
00106 g = y - 0.71414 * v - 0.34414 * u;
00107 b = y + 1.77200 * u;
00108 ret[(i + 1) * 3 + 0] = (unsigned char) (std::min(std::max(r, 0), 255));
00109 ret[(i + 1) * 3 + 1] = (unsigned char) (std::min(std::max(g, 0), 255));
00110 ret[(i + 1) * 3 + 2] = (unsigned char) (std::min(std::max(b, 0), 255));
00111 }
00112 }
00113
00114 void v4l_capture::read_frame(void)
00115 {
00116 struct v4l2_buffer buf;
00117
00118 memset (&(buf), 0, sizeof (buf));
00119
00120 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00121 buf.memory = V4L2_MEMORY_MMAP;
00122
00123 if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) {
00124 perror("VIDIOC_DQBUF");
00125 exit(EXIT_FAILURE);
00126 }
00127 assert(buf.index < n_buffers);
00128
00129 if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
00130 perror("VIDIOC_QBUF");
00131 exit(EXIT_FAILURE);
00132 }
00133 }
00134
00135 void v4l_capture::init_mmap(void)
00136 {
00137 struct v4l2_requestbuffers req;
00138
00139 memset (&(req), 0, sizeof (req));
00140
00141 req.count = 4;
00142 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00143 req.memory = V4L2_MEMORY_MMAP;
00144
00145 if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
00146 perror("VIDIOC_REQBUFS");
00147 exit(EXIT_FAILURE);
00148 }
00149
00150 if (req.count < 2) {
00151 fprintf(stderr, "Insufficient buffer memory on %s\n", dev_name.c_str());
00152 exit(EXIT_FAILURE);
00153 }
00154
00155 buffers = (buffer*)calloc(req.count, sizeof(*buffers));
00156
00157 if (!buffers) {
00158 fprintf(stderr, "Out of memory\n");
00159 exit(EXIT_FAILURE);
00160 }
00161
00162 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
00163 struct v4l2_buffer buf;
00164
00165 memset (&(buf), 0, sizeof (buf));
00166
00167 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00168 buf.memory = V4L2_MEMORY_MMAP;
00169 buf.index = n_buffers;
00170
00171 if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
00172 perror("VIDIOC_QUERYBUF");
00173 exit(EXIT_FAILURE);
00174 }
00175
00176 buffers[n_buffers].length = buf.length;
00177 buffers[n_buffers].start = mmap(NULL ,
00178 buf.length, PROT_READ | PROT_WRITE
00179 ,
00180 MAP_SHARED ,
00181 fd, buf.m.offset);
00182
00183 if (buffers[n_buffers].start == MAP_FAILED) {
00184 perror("mmap");
00185 exit(EXIT_FAILURE);
00186 }
00187 }
00188 }
00189
00190 void v4l_capture::uninit_mmap(void)
00191 {
00192 unsigned int i;
00193
00194 for (i = 0; i < n_buffers; ++i) {
00195 if (munmap(buffers[i].start, buffers[i].length) == -1) {
00196 perror("munmap");
00197 exit(EXIT_FAILURE);
00198 }
00199 }
00200 }
00201
00202 void v4l_capture::init_device(void)
00203 {
00204 struct v4l2_capability cap;
00205 struct v4l2_format fmt;
00206
00207 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
00208 if (EINVAL == errno) {
00209 fprintf(stderr, "%s is no V4L2 device\n", dev_name.c_str());
00210 }
00211 perror("VIDIOC_QUERYCAP");
00212 exit(EXIT_FAILURE);
00213 }
00214
00215 fprintf(stderr, "video capabilities\n");
00216 fprintf(stderr, "cap.driver = %s\n", cap.driver);
00217 fprintf(stderr, "cap.card = %s\n", cap.card);
00218 fprintf(stderr, "cap.buf_info = %s\n", cap.bus_info);
00219 fprintf(stderr, "cap.version = %d\n", cap.version);
00220 fprintf(stderr, "cap.capabilities = 0x%08x ", cap.capabilities);
00221 if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
00222 fprintf(stderr, " VIDEO_CAPTURE");
00223 if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
00224 fprintf(stderr, " VIDEO_OUTPUT");
00225 if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
00226 fprintf(stderr, " VIDEO_OVERLAY");
00227 if (cap.capabilities & V4L2_CAP_VBI_CAPTURE)
00228 fprintf(stderr, " VBI_CAPTURE");
00229 if (cap.capabilities & V4L2_CAP_VBI_OUTPUT)
00230 fprintf(stderr, " VBI_OUTPUT");
00231 #ifdef V4L2_CAP_SLICED_VBI_CAPTURE
00232 if (cap.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE)
00233 fprintf(stderr, " SLICED_VBI_CAPTURE");
00234 #endif
00235 #ifdef V4L2_CAP_SLICED_VBI_OUTPUT
00236 if (cap.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
00237 fprintf(stderr, " VBI_SLICED_OUTPUT");
00238 #endif
00239 if (cap.capabilities & V4L2_CAP_RDS_CAPTURE)
00240 fprintf(stderr, " RDS_CAPTURE");
00241 #if V4L2_CAP_VIDEO_OUTPUT_OVERLAY
00242 if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
00243 fprintf(stderr, " VIDEO_OUTPUT_OVERLAY");
00244 #endif
00245 if (cap.capabilities & V4L2_CAP_TUNER)
00246 fprintf(stderr, " TUNER");
00247 if (cap.capabilities & V4L2_CAP_AUDIO)
00248 fprintf(stderr, " AUDIO");
00249 if (cap.capabilities & V4L2_CAP_RADIO)
00250 fprintf(stderr, " RADIO");
00251 if (cap.capabilities & V4L2_CAP_READWRITE)
00252 fprintf(stderr, " READWRITE");
00253 if (cap.capabilities & V4L2_CAP_ASYNCIO)
00254 fprintf(stderr, " ASYNCIO");
00255 if (cap.capabilities & V4L2_CAP_STREAMING)
00256 fprintf(stderr, " STREAMING");
00257 fprintf(stderr, "\n");
00258
00259 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
00260 fprintf(stderr, "%s is no video capture device\n", dev_name.c_str());
00261 exit(EXIT_FAILURE);
00262 }
00263
00264 memset (&(fmt), 0, sizeof (fmt));
00265
00266 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00267 fmt.fmt.pix.width = width;
00268 fmt.fmt.pix.height = height;
00269 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
00270 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
00271
00272 if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
00273 perror("VIDIOC_S_FMT");
00274 exit(EXIT_FAILURE);
00275 }
00276
00277 init_mmap();
00278 }
00279
00280 void v4l_capture::uninit_device(void)
00281 {
00282 uninit_mmap();
00283 free(buffers);
00284 }
00285
00286 bool v4l_capture::start_capturing(void)
00287 {
00288 unsigned int i;
00289 enum v4l2_buf_type type;
00290
00291 for (i = 0; i < n_buffers; ++i) {
00292 struct v4l2_buffer buf;
00293
00294 memset (&(buf), 0, sizeof (buf));
00295
00296 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00297 buf.memory = V4L2_MEMORY_MMAP;
00298 buf.index = i;
00299
00300 if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
00301 perror("VIDIOC_QBUF");
00302 return false;
00303 }
00304 }
00305
00306 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00307
00308 if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) {
00309 perror("VIDIOC_STREAMON");
00310 return false;
00311 }
00312 return true;
00313 }
00314
00315 void v4l_capture::stop_capturing(void)
00316 {
00317 enum v4l2_buf_type type;
00318
00319 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00320
00321 if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) {
00322 perror("VIDIOC_STREAMOFF");
00323 exit(EXIT_FAILURE);
00324 }
00325
00326 }