core/vidl/vidl_v4l_istream.cxx
Go to the documentation of this file.
00001 // This is core/vidl/vidl_v4l_istream.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Brendan McCane
00008 // \date   16 Mar 2006
00009 //
00010 //-----------------------------------------------------------------------------
00011 
00012 #include "vidl_v4l_ulong_fix.h" // include first to fix linux/videodev.h ulong problem
00013 #include "vidl_v4l_istream.h"
00014 #include "vidl_v4l_params.h"
00015 #include "vidl_pixel_format.h"
00016 #include "vidl_frame.h"
00017 #include <vcl_cstdio.h> // for std::perror()
00018 
00019 //: Destructor
00020 vidl_v4l_istream::~vidl_v4l_istream()
00021 {
00022     close();
00023 }
00024 
00025 //: open a device
00026 bool vidl_v4l_istream::open(const vcl_string &device_name)
00027 {
00028     close();
00029     frame_number_ = 0;
00030 
00031     fd_ = ::open(device_name.c_str(), O_RDWR);
00032 
00033     if (fd_==-1)
00034         vcl_perror("problem with v4l");
00035 
00036     if (-1 == ioctl (fd_, VIDIOCGCAP, &vc)) {
00037         vcl_perror ("VIDIOCGCAP");
00038         return false;
00039     }
00040     vcl_cout << "name = " << vc.name << vcl_endl
00041              << "type = " << vc.type << vcl_endl
00042              << "channels = " << vc.channels << vcl_endl
00043              << "maxwidth = " << vc.maxwidth << vcl_endl
00044              << "maxheight = " << vc.maxheight << vcl_endl;
00045 
00046     if (-1 == ioctl (fd_, VIDIOCGWIN, &vw)) {
00047         vcl_perror ("VIDIOCGWIN");
00048         return false;
00049     }
00050     defaults_.ni_ = vw.width;
00051     defaults_.nj_ = vw.height;
00052 
00053     if (-1 == ioctl (fd_, VIDIOCGPICT, &vp)) {
00054         vcl_perror ("VIDIOCGPICT");
00055         return false;
00056     }
00057 
00058     defaults_.brightness_ = vp.brightness;
00059     defaults_.hue_ = vp.hue;
00060     defaults_.colour_ = vp.colour;
00061     defaults_.contrast_ = vp.contrast;
00062     defaults_.whiteness_ = vp.whiteness;
00063     defaults_.depth_ = vp.depth;
00064     defaults_.pixel_format_ = vidl_v4l_params::v4lpf_to_vidlpf(vp.palette);
00065     if (defaults_.pixel_format_ ==  VIDL_PIXEL_FORMAT_UNKNOWN)
00066         defaults_.pixel_format_ = VIDL_PIXEL_FORMAT_YUV_420P;
00067 
00068     if (-1 == ioctl (fd_, VIDIOCGMBUF, &vm)) {
00069         vcl_perror ("VIDIOCGMBUF");
00070         return false;
00071     }
00072     // for the moment just use one mmapped frame
00073     buf = mmap(0, vm.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_,0);
00074     if (buf==(unsigned char *)-1)
00075     {
00076         vcl_perror("problem with mmap");
00077         close();
00078         return false;
00079     }
00080 
00081     // this looks a bit redundant (and it is), but some other things
00082     // are also set in set_params besides the actual driver controls
00083     bool sp_ret = set_params(defaults_);
00084     vcl_cerr << "sp_ret = " << sp_ret << vcl_endl;
00085     // serious problems if we can't set the params to the defaults
00086     if (!sp_ret)
00087     {
00088         vcl_cerr << "Problem in constructor, can't set camera to default\n"
00089                  << "Trying to continue anyway ...\n";
00090     }
00091 
00092     return sp_ret;
00093 }
00094 
00095 //: return true if the stream is open for reading
00096 bool vidl_v4l_istream::is_open() const
00097 {
00098     return fd_>0;
00099 }
00100 
00101 //: return true if the stream is in a valid state
00102 bool vidl_v4l_istream::is_valid() const
00103 {
00104     return is_open();
00105 }
00106 
00107 //: close the stream
00108 void vidl_v4l_istream::close()
00109 {
00110     ::close(fd_);
00111     fd_ = -1;
00112 }
00113 
00114 //: set the parameters for this stream.
00115 // If all the parameters are set as requested, return true; else return false
00116 bool vidl_v4l_istream::set_params(const vidl_v4l_params &p)
00117 {
00118     bool success=true;
00119 
00120     params_ = p;
00121 
00122     vw.width = p.ni_;
00123     vw.height = p.nj_;
00124     if (-1 == ioctl (fd_, VIDIOCSWIN, &vw)) {
00125         vcl_cerr << "VIDIOCSWIN\n";
00126         vcl_perror ("VIDIOCGWIN");
00127         return false;
00128     }
00129     if (-1 == ioctl (fd_, VIDIOCGWIN, &vw)) {
00130         vcl_cerr << "VIDIOCGWIN\n";
00131         vcl_perror ("VIDIOCGWIN");
00132         return false;
00133     }
00134     if ((vw.width!=p.ni_)||(vw.height!=p.nj_))
00135     {
00136         vcl_cerr << "width not equal to default\n";
00137         success = false;
00138     }
00139 
00140     vp.brightness = p.brightness_;
00141     vp.hue =  p.hue_;
00142     vp.colour = p.colour_;
00143     vp.contrast = p.contrast_;
00144     vp.whiteness = p.whiteness_;
00145     vp.depth = p.depth_;
00146     vp.palette = vidl_v4l_params::vidlpf_to_v4lpf(p.pixel_format_);
00147     if (-1 == ioctl (fd_, VIDIOCSPICT, &vp)) {
00148         vcl_cerr << "VIDIOCSPICT\n";
00149         vcl_perror ("VIDIOCSPICT");
00150         return false;
00151     }
00152     if (-1 == ioctl (fd_, VIDIOCGPICT, &vp)) {
00153         vcl_cerr << "VIDIOCGPICT\n";
00154         vcl_perror ("VIDIOCGPICT");
00155         return false;
00156     }
00157 
00158     if (vp.brightness != p.brightness_)
00159     {
00160         success = false;
00161         vcl_cerr << "vp.brightness = " << vp.brightness << vcl_endl
00162                  << "p.brightness = " << p.brightness_ << vcl_endl;
00163     }
00164     if (vp.hue != p.hue_)
00165     {
00166         success = false;
00167         vcl_cerr << "vp.hue = " << vp.hue << vcl_endl
00168                  << "p.hue = " << p.hue_ << vcl_endl;
00169     }
00170     if (vp.colour != p.colour_)
00171     {
00172         success = false;
00173         vcl_cerr << "vp.colour = " << vp.colour << vcl_endl
00174                  << "p.colour = " << p.colour_ << vcl_endl;
00175     }
00176     if (vp.contrast != p.contrast_)
00177     {
00178         success = false;
00179         vcl_cerr << "vp.contrast = " << vp.contrast << vcl_endl
00180                  << "p.contrast = " << p.contrast_ << vcl_endl;
00181     }
00182     if (vp.whiteness != p.whiteness_)
00183     {
00184         success = false;
00185         vcl_cerr << "vp.whiteness = " << vp.whiteness << vcl_endl
00186                  << "p.whiteness = " << p.whiteness_ << vcl_endl;
00187     }
00188     if (vp.depth != p.depth_)
00189     {
00190         success = false;
00191         vcl_cerr << "vp.depth = " << vp.depth << vcl_endl
00192                  << "p.depth = " << p.depth_ << vcl_endl;
00193     }
00194     if (vp.palette != vidl_v4l_params::vidlpf_to_v4lpf(p.pixel_format_))
00195     {
00196         success = false;
00197         vcl_cerr << "vp.palette = " << vp.palette << vcl_endl
00198                  << "p.pixel_format = " << p.pixel_format_ << vcl_endl;
00199     }
00200 
00201     mm.width = vw.width;
00202     mm.height = vw.height;
00203     mm.format = vp.palette;
00204     mm.frame = 0;
00205 
00206     cur_frame_ = new vidl_shared_frame(
00207         buf, vw.width, vw.height, vidl_v4l_params::v4lpf_to_vidlpf(vp.palette));
00208 
00209     vcl_cerr << "success = " << success << vcl_endl;
00210     return success;
00211 }
00212 
00213 //: advance to the next frame (but don't acquire an image)?
00214 // I'm quite confused by this description - I don't even know what it means.
00215 // I'm using the vidl_dc1394_istream as a model here which clearly
00216 // advances and acquires - contrary to the first sentence description
00217 bool vidl_v4l_istream::advance()
00218 {
00219     if (ioctl(fd_, VIDIOCMCAPTURE, &mm)<0) {
00220         vcl_perror("VIDIOCMCAPTURE");
00221         return false;
00222     }
00223 
00224     int i = -1;
00225 
00226     // shouldn't have to loop here, but apparently we do. Something to
00227     // do with interrupts.
00228     while (i < 0) {
00229         i = ioctl(fd_, VIDIOCSYNC, &mm.frame);
00230         if (i < 0 && errno == EINTR){
00231             vcl_perror("VIDIOCSYNC problem");
00232             continue;
00233         }
00234         if (i < 0) {
00235             vcl_perror("VIDIOCSYNC");
00236             // You may want to exit here, because something has gone
00237             // pretty badly wrong...
00238             return false;
00239         }
00240         break;
00241     }
00242 
00243     frame_number_++;
00244 
00245     return true;
00246 }
00247 
00248 //: Read the next frame from the stream
00249 //  Not sure why this one is needed ...
00250 vidl_frame_sptr vidl_v4l_istream::read_frame()
00251 {
00252     if (advance())
00253         return current_frame();
00254     return NULL;
00255 }
00256 
00257 
00258 //: Return the width of each frame
00259 unsigned int vidl_v4l_istream::width() const
00260 {
00261   if (!is_open())
00262     return 0;
00263   return cur_frame_->ni();
00264 }
00265 
00266 
00267 //: Return the height of each frame
00268 unsigned int vidl_v4l_istream::height() const
00269 {
00270   if (!is_open())
00271     return 0;
00272   return cur_frame_->nj();
00273 }
00274 
00275 
00276 //: Return the pixel format
00277 vidl_pixel_format vidl_v4l_istream::format() const
00278 {
00279   if (!is_open())
00280     return VIDL_PIXEL_FORMAT_UNKNOWN;
00281   return cur_frame_->pixel_format();
00282 }
00283 
00284 
00285 //: Return the frame rate (FPS, 0.0 if unspecified)
00286 double vidl_v4l_istream::frame_rate() const
00287 {
00288   // TODO return a frame rate here if v4l can be
00289   // configured for a constant frame rate
00290   return 0.0;
00291 }