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