v4l1.cpp

00001 
00002 /***************************************************************************
00003  *  v4l1.cpp - Implementation to access V4L cam
00004  *
00005  *  Generated: Fri Mar 11 17:48:27 2005
00006  *  Copyright  2005  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <core/exception.h>
00025 #include <core/exceptions/software.h>
00026 
00027 #include <cams/v4l1.h>
00028 #include <fvutils/color/colorspaces.h>
00029 #include <fvutils/color/rgb.h>
00030 #include <fvutils/system/camargp.h>
00031 
00032 #include <cstdio>
00033 #include <cstdlib>
00034 #include <sys/stat.h>
00035 #include <sys/ioctl.h>
00036 #include <sys/mman.h>
00037 #include <sys/time.h>   /* gettimeofday() */
00038 #include <fcntl.h>
00039 #include <unistd.h>
00040 #include <linux/types.h>
00041 #include <errno.h>
00042 #include <cstring>
00043 #include <iostream>
00044 #include <cassert>
00045 #include <sys/types.h>
00046 #include <linux/videodev.h>
00047 
00048 
00049 using namespace std;
00050 using namespace fawkes;
00051 
00052 namespace firevision {
00053 #if 0 /* just to make Emacs auto-indent happy */
00054 }
00055 #endif
00056 
00057 /// @cond INTERNALS
00058 
00059 class V4L1CameraData
00060 {
00061  public:
00062   V4L1CameraData(const char *device_name)
00063   {
00064     this->device_name = strdup(device_name);
00065   }
00066 
00067   ~V4L1CameraData()
00068   {
00069     free(device_name);
00070   }
00071 
00072  public:
00073   char *device_name;
00074 
00075   /* V4L1 stuff */
00076   struct video_capability  capabilities;          // Device Capabilities: Can overlay, Number of channels, etc
00077   struct video_buffer      vbuffer;               // information about buffer
00078   struct video_window      window;                // Window Information: Size, Depth, etc
00079   struct video_channel    *channel;               // Channels information: Channel[0] holds information for channel 0 and so on...
00080   struct video_picture     picture;               // Picture information: Palette, contrast, hue, etc
00081   struct video_tuner      *tuner;                 // Tuner Information: if the card has tuners...
00082   struct video_audio       audio;                 // If the card has audio
00083   struct video_mbuf        captured_frame_buffer; // Information for the frame to be captured: norm, palette, etc
00084   struct video_mmap       *buf_v4l;               // mmap() buffer VIDIOCMCAPTURE
00085 };
00086 
00087 /// @endcond
00088 
00089 /** @class V4L1Camera <cams/v4l1.h>
00090  * Video4Linux 1 camera implementation.
00091  */
00092 
00093 /** Constructor.
00094  * @param device_name device file name (e.g. /dev/video0)
00095  */
00096 V4L1Camera::V4L1Camera(const char *device_name)
00097 {
00098   started = opened = false;
00099   __data = new V4L1CameraData(device_name);
00100 }
00101 
00102 
00103 /** Constructor.
00104  * Initialize camera with parameters from camera argument parser.
00105  * Supported arguments:
00106  * - device=DEV, device file, for example /dev/video0
00107  * @param cap camera argument parser
00108  */
00109 V4L1Camera::V4L1Camera(const CameraArgumentParser *cap)
00110 {
00111   started = opened = false;
00112   if ( cap->has("device") ) {
00113     __data = new V4L1CameraData(cap->get("device").c_str());
00114   } else {
00115     throw MissingParameterException("Missing device for V4L1Camera");
00116   }
00117 }
00118 
00119 /** Protected Constructor.
00120  * Gets called from V4LCamera, when the device has already been opened
00121  * and determined to be a V4L1 device.
00122  * @param device_name device file name (e.g. /dev/video0)
00123  * @param dev file descriptor of the opened device
00124  */
00125 V4L1Camera::V4L1Camera(const char *device_name, int dev)
00126 {
00127   started = opened = false;
00128   __data = new V4L1CameraData(device_name);
00129   this->dev = dev;
00130 
00131   // getting grabber info in capabilities struct
00132   if ( (ioctl(dev, VIDIOCGCAP, &(__data->capabilities))) == -1 ) {
00133     throw Exception("V4L1Cam: Could not get capabilities");
00134   }
00135 
00136   post_open();
00137 }
00138 
00139 
00140 /** Destructor. */
00141 V4L1Camera::~V4L1Camera()
00142 {
00143   delete __data;
00144 }
00145 
00146 
00147 void
00148 V4L1Camera::open()
00149 {
00150   opened = false;
00151 
00152   dev = ::open(__data->device_name, O_RDWR);
00153   if (dev < 0) {
00154     throw Exception("V4L1Cam: Could not open device");
00155   }
00156 
00157   // getting grabber info in capabilities struct
00158   if ( (ioctl(dev, VIDIOCGCAP, &(__data->capabilities))) == -1 ) {
00159     throw Exception("V4L1Cam: Could not get capabilities");
00160   }
00161 
00162   post_open();
00163 }
00164 
00165 /**
00166  * Post-open() operations
00167  * @param dev file descriptor of the opened device
00168  */
00169 void
00170 V4L1Camera::post_open()
00171 {
00172   // Capture window information
00173   if ( (ioctl(dev, VIDIOCGWIN, &__data->window)) == -1) {
00174     throw Exception("V4L1Cam: Could not get window information");
00175   }
00176 
00177   // Picture information
00178   if ( (ioctl(dev, VIDIOCGPICT, &__data->picture)) == -1) {
00179     throw Exception("V4L1Cam: Could not get window information");
00180   }
00181 
00182   ///Video Channel Information or Video Sources
00183   ///Allocate space for each channel
00184   __data->channel = (struct video_channel*)malloc(sizeof(struct video_channel)*(__data->capabilities.channels+1));
00185   for(int ch = 0; ch < __data->capabilities.channels; ch++) {
00186     __data->channel[ch].norm = 0;
00187     if ( (ioctl(dev, VIDIOCSCHAN, &__data->channel[ch])) == -1) {
00188       printf("V4L1Cam: Could not get channel information for channel %i: %s", ch, strerror(errno));
00189     }
00190   }
00191 
00192   ///Trying to capture through read()
00193   if (ioctl (dev, VIDIOCGMBUF, __data->captured_frame_buffer) == -1) {
00194     capture_method = READ;
00195     frame_buffer = (unsigned char *)malloc(__data->window.width * __data->window.height * RGB_PIXEL_SIZE);
00196   } else {
00197     capture_method = MMAP;
00198     frame_buffer = (unsigned char*)mmap (0, __data->captured_frame_buffer.size, PROT_READ | PROT_WRITE, MAP_SHARED, dev, 0);
00199     if ((unsigned char *) -1 == (unsigned char *)frame_buffer) {
00200       throw Exception("V4L1Cam: Cannot initialize mmap region");
00201     }
00202   }
00203 
00204   __data->buf_v4l = NULL;
00205 
00206   opened = true;
00207 }
00208 
00209 
00210 void
00211 V4L1Camera::start()
00212 {
00213 
00214   started = false;
00215   if (!opened) {
00216     throw Exception("V4L1Cam: Trying to start closed cam!");
00217   }
00218 
00219   started = true;
00220 }
00221 
00222 
00223 void
00224 V4L1Camera::stop()
00225 {
00226   started = false;
00227 }
00228 
00229 
00230 void
00231 V4L1Camera::print_info()
00232 {
00233 
00234   if (! opened) return;
00235 
00236   cout << endl << "CAPABILITIES" << endl
00237        << "===========================================================================" << endl;
00238 
00239   if(__data->capabilities.type & VID_TYPE_CAPTURE)
00240     cout << " + Can capture to memory" << endl;
00241   if(__data->capabilities.type & VID_TYPE_TUNER)
00242     cout << " + Has a tuner of some form" << endl;
00243   if(__data->capabilities.type & VID_TYPE_TELETEXT)
00244     cout << " + Has teletext capability" << endl;
00245   if(__data->capabilities.type & VID_TYPE_OVERLAY)
00246     cout << " + Can overlay its image onto the frame buffer" << endl;
00247   if(__data->capabilities.type & VID_TYPE_CHROMAKEY)
00248     cout << " + Overlay is Chromakeyed" << endl;
00249   if(__data->capabilities.type & VID_TYPE_CLIPPING)
00250     cout << " + Overlay clipping is supported" << endl;
00251   if(__data->capabilities.type & VID_TYPE_FRAMERAM)
00252     cout << " + Overlay overwrites frame buffer memory" << endl;
00253   if(__data->capabilities.type & VID_TYPE_SCALES)
00254     cout << " + The hardware supports image scaling" << endl;
00255   if(__data->capabilities.type & VID_TYPE_MONOCHROME)
00256     cout << " + Image capture is grey scale only" << endl;
00257   if(__data->capabilities.type & VID_TYPE_SUBCAPTURE)
00258     cout << " + Can subcapture" << endl;
00259 
00260   cout << endl;
00261   cout << " Number of Channels ='" << __data->capabilities.channels << "'" << endl;
00262   cout << " Number of Audio Devices ='" << __data->capabilities.audios << "'" << endl;
00263   cout << " Maximum Capture Width ='" << __data->capabilities.maxwidth << "'" << endl;
00264   cout << " Maximum Capture Height ='" << __data->capabilities.maxheight << "'" << endl;
00265   cout << " Minimum Capture Width ='" << __data->capabilities.minwidth << "'" << endl;
00266   cout << " Minimum Capture Height ='" << __data->capabilities.minheight << "'" << endl;
00267 
00268 
00269 
00270 
00271   cout << endl << "CAPTURE WINDOW INFO" << endl
00272        << "===========================================================================" << endl;
00273 
00274   cout << " X Coord in X window Format:  " << __data->window.x << endl;
00275   cout << " Y Coord in X window Format:  " << __data->window.y << endl;
00276   cout << " Width of the Image Capture:  " << __data->window.width << endl;
00277   cout << " Height of the Image Capture: " << __data->window.height << endl;
00278   cout << " ChromaKey:                   " << __data->window.chromakey  << endl;
00279 
00280 
00281 
00282 
00283   cout << endl << "DEVICE PICTURE INFO" << endl
00284        << "===========================================================================" << endl;
00285 
00286   cout << " Picture Brightness: " << __data->picture.brightness << endl;
00287   cout << " Picture        Hue: " << __data->picture.hue << endl;
00288   cout << " Picture     Colour: " << __data->picture.colour << endl;
00289   cout << " Picture   Contrast: " << __data->picture.contrast << endl;
00290   cout << " Picture  Whiteness: " << __data->picture.whiteness << endl;
00291   cout << " Picture      Depth: " << __data->picture.depth << endl;
00292   cout << " Picture    Palette: " << __data->picture.palette << " (";
00293 
00294   if(__data->picture.palette == VIDEO_PALETTE_GREY)
00295     cout << "VIDEO_PALETTE_GRAY";
00296   if(__data->picture.palette == VIDEO_PALETTE_HI240)
00297     cout << "VIDEO_PALETTE_HI240";
00298   if(__data->picture.palette == VIDEO_PALETTE_RGB565)
00299     cout << "VIDEO_PALETTE_RGB565";
00300   if(__data->picture.palette == VIDEO_PALETTE_RGB555)
00301     cout << "VIDEO_PALETTE_RGB555";
00302   if(__data->picture.palette == VIDEO_PALETTE_RGB24)
00303     cout << "VIDEO_PALETTE_RGB24";
00304   if(__data->picture.palette == VIDEO_PALETTE_RGB32)
00305     cout << "VIDEO_PALETTE_RGB32";
00306   if(__data->picture.palette == VIDEO_PALETTE_YUV422)
00307     cout << "VIDEO_PALETTE_YUV422";
00308   if(__data->picture.palette == VIDEO_PALETTE_YUYV)
00309     cout << "VIDEO_PALETTE_YUYV";
00310   if(__data->picture.palette == VIDEO_PALETTE_UYVY)
00311     cout << "VIDEO_PALETTE_UYVY";
00312   if(__data->picture.palette == VIDEO_PALETTE_YUV420)
00313     cout << "VIDEO_PALETTE_YUV420";
00314   if(__data->picture.palette == VIDEO_PALETTE_YUV411)
00315     cout << "VIDEO_PALETTE_YUV411";
00316   if(__data->picture.palette == VIDEO_PALETTE_RAW)
00317     cout << "VIDEO_PALETTE_RAW";
00318   if(__data->picture.palette == VIDEO_PALETTE_YUV422P)
00319     cout << "VIDEO_PALETTE_YUV422P";
00320   if(__data->picture.palette == VIDEO_PALETTE_YUV411P)
00321     cout << "VIDEO_PALETTE_YUV411P";
00322 
00323   cout << ")" << endl;
00324 
00325 
00326 
00327   cout << endl << "VIDEO SOURCE INFO" << endl
00328        << "===========================================================================" << endl;
00329 
00330   cout << " Channel Number or Video Source Number: " << __data->channel->channel << endl;
00331   cout << " Channel Name:                          " << __data->channel->name << endl;
00332   cout << " Number of Tuners for this source:      " << __data->channel->tuners << endl;
00333   cout << " Channel Norm:                          " << __data->channel->norm << endl;
00334   if(__data->channel->flags & VIDEO_VC_TUNER)
00335     cout << " + This channel source has tuners" << endl;
00336   if(__data->channel->flags & VIDEO_VC_AUDIO)
00337     cout << " + This channel source has audio" << endl;
00338   if(__data->channel->type & VIDEO_TYPE_TV)
00339     cout << " + This channel source is a TV input" << endl;
00340   if(__data->channel->type & VIDEO_TYPE_CAMERA)
00341     cout << " + This channel source is a Camera input" << endl;
00342 
00343 
00344 
00345 
00346   cout << endl << "FRAME BUFFER INFO" << endl
00347        << "===========================================================================" << endl;
00348 
00349   cout << " Base Physical Address:  " << __data->vbuffer.base << endl;
00350   cout << " Height of Frame Buffer: " << __data->vbuffer.height << endl;
00351   cout << " Width of Frame Buffer:  " << __data->vbuffer.width << endl;
00352   cout << " Depth of Frame Buffer:  " << __data->vbuffer.depth << endl;
00353   cout << " Bytes Per Line:         " << __data->vbuffer.bytesperline << endl;
00354 
00355 
00356 
00357   /* Which channel!?
00358   cout << endl << "CHANNEL INFO" << endl
00359        << "===========================================================================" << endl;
00360 
00361   cout << " Channel:          " << ch << " - " << channel[ch].name << endl;
00362   cout << " Number of Tuners: " << channel[0].tuners << endl;
00363   cout << " Input Type:       " << channel[ch].type << endl;
00364   cout << " Flags: " << endl;
00365   if(channel[0].flags & VIDEO_VC_TUNER)
00366     cout << " + This Channel Source has Tuners" << endl;
00367   if(channel[0].flags & VIDEO_VC_AUDIO)
00368     cout << " + This Channel Source has Audio" << endl;
00369   //  if(channel[0].flags & VIDEO_VC_NORM)
00370   //cout << " \tThis Channel Source has Norm\n");
00371   cout << " Norm for Channel: '" << channel[0].norm << "'" << endl;
00372   */
00373 
00374 }
00375 
00376 
00377 void
00378 V4L1Camera::capture()
00379 {
00380 
00381   if (capture_method == READ) {
00382     int len = read(dev, frame_buffer, __data->window.width * __data->window.height * RGB_PIXEL_SIZE);
00383     if (len < 0) {
00384       throw Exception("V4L1Cam: Could not capture frame");
00385     }
00386   } else {
00387 
00388     __data->buf_v4l = (struct video_mmap*)malloc(__data->captured_frame_buffer.frames * sizeof(struct video_mmap));
00389 
00390     ///Setting up the palette, size of frame and which frame to capture
00391     __data->buf_v4l[0].format = __data->picture.palette;
00392     __data->buf_v4l[0].frame  = 0;
00393     __data->buf_v4l[0].width  = __data->window.width;
00394     __data->buf_v4l[0].height = __data->window.height;
00395 
00396     if (ioctl (dev, VIDIOCMCAPTURE, &(__data->buf_v4l[0])) == -1) {
00397       throw Exception("V4L1Cam: Could not capture frame (VIDIOCMCAPTURE)");
00398     }
00399     ///Waiting for the frame to finish
00400     int Frame = 0;
00401     if (ioctl (dev, VIDIOCSYNC, &Frame) == -1) {
00402       throw Exception("V4L1Cam: Could not capture frame (VIDIOCSYNC)");
00403     }
00404   }
00405 }
00406 
00407 
00408 void
00409 V4L1Camera::dispose_buffer()
00410 {
00411   if (capture_method == MMAP) {
00412     if (__data->buf_v4l != NULL) {
00413       free(__data->buf_v4l);
00414       __data->buf_v4l = NULL;
00415     }
00416     munmap(frame_buffer, __data->captured_frame_buffer.size);
00417   }
00418 }
00419 
00420 
00421 unsigned char*
00422 V4L1Camera::buffer()
00423 {
00424   return frame_buffer;
00425 }
00426 
00427 unsigned int
00428 V4L1Camera::buffer_size()
00429 {
00430   return colorspace_buffer_size(RGB, __data->window.width, __data->window.height);
00431 }
00432 
00433 void
00434 V4L1Camera::close()
00435 {
00436   if (opened) {
00437     ::close(dev);
00438   }
00439 }
00440 
00441 unsigned int
00442 V4L1Camera::pixel_width()
00443 {
00444   if (opened) {
00445     return __data->window.width;
00446   } else {
00447     throw Exception("V4L1Cam::pixel_width(): Camera not opened");
00448   }
00449 }
00450 
00451 unsigned int
00452 V4L1Camera::pixel_height()
00453 {
00454   if (opened) {
00455     return __data->window.height;
00456   } else {
00457     throw Exception("V4L1Cam::pixel_height(): Camera not opened");
00458   }
00459 }
00460 
00461 
00462 colorspace_t
00463 V4L1Camera::colorspace()
00464 {
00465   return BGR;
00466 }
00467 
00468 
00469 void
00470 V4L1Camera::flush()
00471 {
00472 }
00473 
00474 
00475 bool
00476 V4L1Camera::ready()
00477 {
00478   return started;
00479 }
00480 
00481 
00482 void
00483 V4L1Camera::set_image_number(unsigned int n)
00484 {
00485 }
00486 
00487 } // end namespace firevision