// video4linux.cc // robert - programme du robot 2005. {{{ // // Copyright (C) 2005 Nicolas Schodet // // Robot APB Team/Efrei 2005. // Web: http://assos.efrei.fr/robot/ // Email: robot AT efrei DOT fr // // 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. // // }}} #include "video4linux.hh" #include "utils/errno_exception.hh" #include "utils/fd_set.hh" #include #include #include #include #include #include /// Constructeur. Video4Linux::Video4Linux (const char *dev, Image::PixelFormat pixelFormat, int brightness /*58000*/) : fd_ (-1), width_ (-1), height_ (-1), pixelFormat_ (pixelFormat), rgb_ (pixelFormat == Image::rgb || pixelFormat == Image::bgr), brightness_ (brightness), contrast_ (32768) { if (pixelFormat == Image::hsi) throw std::invalid_argument ("hsi not supported by Video4Linux"); open (dev); } /// Destructeur. Video4Linux::~Video4Linux (void) { close (); } /// Lit une image, lance une exception en cas d'erreur. void Video4Linux::read (uint8_t *buf, unsigned size) { if (buf && size != width_ * height_ * bpp_) throw std::invalid_argument ("Video4Linux::read"); // Mmap. void *map; map = mmap (0, bufSize_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0); // Capture. video_mmap mmap; mmap.format = rgb_ ? VIDEO_PALETTE_RGB24 : VIDEO_PALETTE_YUV422; mmap.frame = 0; mmap.width = width_; mmap.height = height_; ioctl (fd_, VIDIOCMCAPTURE, &mmap); // Sync. ioctl (fd_, VIDIOCSYNC, &mmap); // Copy. if (buf) { unsigned char *src = reinterpret_cast (map); unsigned char *dst = reinterpret_cast (buf); switch (pixelFormat_) { case Image::rgb: for (int i = 0; i < width_ * height_; ++i) { *dst++ = src[2]; *dst++ = src[1]; *dst++ = src[0]; src += 3; } break; memcpy (buf, map, size); break; case Image::yuv: for (int i = 0; i < width_ * height_ / 2; ++i) { *dst++ = src[0]; // Y1 *dst++ = src[1]; // U *dst++ = src[3]; // V *dst++ = src[2]; // Y2 *dst++ = src[1]; // U *dst++ = src[3]; // V src += 4; } break; case Image::bgr: case Image::yuv422: case Image::hsi: memcpy (buf, map, size); break; } } // Munmap. munmap (map, bufSize_); } /// Calibre la caméra. void Video4Linux::calibrate (void) { for (int i = 0; i < 100; ++i) read (0, 0); } /// Attend qu'une image soit disponible, retourne true si oui. bool Video4Linux::wait (int timeout/*-1*/) { FdSet fds; fds.set (fd_); return fds.wait (timeout); } /// Ouvre le périphérique. void Video4Linux::open (const char *dev) { if (fd_ != -1) close (); fd_ = ::open (dev, O_RDWR); if (fd_ == -1) throw errno_exception (dev, errno); // On récupère les cap. video_capability cap; if (ioctl (fd_, VIDIOCGCAP, &cap) == -1) throw errno_exception (dev, errno); // On veut du RGB24. video_picture pic; ioctl (fd_, VIDIOCGPICT, &pic); pic.palette = rgb_ ? VIDEO_PALETTE_RGB24 : VIDEO_PALETTE_YUV422; bpp_ = Image::getBytePerPixel (pixelFormat_); pic.brightness = brightness_; pic.contrast = contrast_; ioctl (fd_, VIDIOCSPICT, &pic); // Channel. video_channel chn; ioctl (fd_, VIDIOCGCHAN, &chn); chn.channel = 0; chn.norm = VIDEO_MODE_PAL; ioctl (fd_, VIDIOCSCHAN, &chn); // Récupères les infos sur la camera. video_window win; ioctl (fd_, VIDIOCGWIN, &win); width_ = win.width; height_ = win.height; // Initialisation mmap. video_mbuf mbuf; ioctl (fd_, VIDIOCGMBUF, &mbuf); bufSize_ = mbuf.size; } /// Ferme le périphérique. void Video4Linux::close (void) { ::close (fd_); }