core/vidl/vidl_v4l2_device.h

Go to the documentation of this file.
00001 // This is core/vidl/vidl_v4l2_device.h
00002 #ifndef vidl_v4l2_device_h_
00003 #define vidl_v4l2_device_h_
00004 //:
00005 // \file
00006 // \brief A class for handling a video device
00007 //
00008 // \author Antonio Garrido
00009 // \verbatim
00010 //  Modifications
00011 //   15 Apr 2009 Created (A. Garrido)
00012 //\endverbatim
00013 
00014 #include "vidl_v4l2_control.h"
00015 #include <vcl_vector.h>
00016 #include <vcl_string.h>
00017 #include <vcl_cassert.h>
00018 #include <vcl_iosfwd.h>
00019 #include <vcl_iostream.h>
00020 extern "C" {
00021 #include <asm/types.h>          /* for videodev2.h */
00022 #include <linux/videodev2.h>
00023 };
00024 
00025 //: A class for handle a video device input
00026 // This class is not finished. I am thinking about adding controls, that is, a number of user-settable controls such as brightness, saturation and so on. but different devices will have different controls available. So, I am thinking about new classes...
00027 class vidl_v4l2_input
00028 {
00029   struct v4l2_input input_;
00030   vidl_v4l2_input (const struct v4l2_input& inp) { input_=inp; }
00031   friend class vidl_v4l2_device;
00032  public:
00033   //: Return name of input
00034   vcl_string name() const { return vcl_string((const char*) input_.name); }
00035   //: Return if the input uses a tuner (RF modulator)
00036   bool is_tuner() const { return input_.type==V4L2_INPUT_TYPE_TUNER; }
00037 };
00038 
00039 //: A class for handle a video device.
00040 // This class is designed to be vidl independent, although it is very easy to create a vidl istream from it.
00041 // It has not been fully tested, although it has been proven to capture images from multiple webcams with a single buffer (default) and has worked properly.
00042 // Generally, the steps to be made for a capture are as follows:
00043 // -# <b>Select input</b>
00044 // -# <b>Select format</b>
00045 // -# <b>Select number of buffers</b>.
00046 // -# <b>Start capturing</b>
00047 // -# <b>Stop capturing</b>
00048 // When a devide is opened, a input and format are selected by default (see vidl_v4l2_device::try_formats function). Then if you start capturing, you will <b>probably</b> get 640x480 frames,  from input 0, using just one buffer with a unknown format (the first one valid for the driver).
00049 // \see vidl_v4l2_devices
00050 class vidl_v4l2_device
00051 {
00052   VCL_SAFE_BOOL_DEFINE;
00053   int fd;
00054 
00055   struct buffer {
00056     void *                  start; // vidl_frame_sptr??
00057     struct v4l2_buffer buf;
00058     //size_t                  length;
00059   };
00060   unsigned int pre_nbuffers; // Number of buffers to create
00061   struct buffer * buffers;
00062   unsigned int n_buffers;
00063   int last_buffer; // last read buffer to enqueue again (-1 if none)
00064   struct v4l2_format fmt; // width=height=0 indicates not stablished
00065   double frame_rate;
00066 
00067   vcl_string dev_name_;
00068   vcl_string card_name_;
00069   mutable vcl_string last_error;
00070   bool capturing; // see start_capturing
00071   vcl_vector<vidl_v4l2_input> inputs_;
00072   vcl_vector<vidl_v4l2_control *> controls_;
00073   void update_controls(); // must be called after input change
00074 
00075   bool open(); // return true if successful
00076   bool initialize_device(); //  return true if successful
00077   bool init_mmap(int reqbuf);
00078   bool uninit_mmap ();
00079   bool close();
00080 
00081   bool is_open() const { return fd!=-1; }
00082   bool is_prepared_for_capturing() const  { return buffers!=0; }
00083   bool good() const { return last_error.size()==0; }
00084 
00085   bool try_formats();
00086 
00087   // non-valid functions
00088   vidl_v4l2_device(const vidl_v4l2_device&);
00089   vidl_v4l2_device& operator= (const vidl_v4l2_device&);
00090 
00091  public:
00092 
00093   //: Constructor
00094   // \param file device name (for example, "/dev/video")
00095   vidl_v4l2_device(const char *file);
00096   ~vidl_v4l2_device();
00097 
00098   //: Reset the device to a initial state
00099   void reset();
00100 
00101   //: Name of the associated file device (same as constructor)
00102   vcl_string device_file() const { return dev_name_; }
00103   //: Friendly name of the device.
00104   vcl_string card_name() const { return card_name_; }
00105   //: Number of inputs in device
00106   unsigned int n_inputs() const { return inputs_.size(); }
00107   //: Inputs been used (0 to ninputs-1)
00108   // if equal to ninputs, indicates unknown
00109   // \see ninputs
00110   unsigned int current_input() const;
00111   //: Return input number i (0 .. ninputs-1)
00112   const vidl_v4l2_input& input(int i) const { return inputs_.at(i);}
00113 
00114   //: Select input i
00115   // \return if successful
00116   bool set_input(unsigned int i);
00117 
00118   //: Select a new format.
00119   // Device try automatically different formats (\see try_formats()). Then this function could be ignored if you don't mind the format. Usually, user wants a concrete pixel format or, simply, change width and height.
00120   // \param fourcode A four character code defined in v4l2 (see v4l2 specification and vidl_pixel_format.h) indicating pixel encoding
00121   // \param width can be changed by drivers to the closest possible value
00122   // \param height can be changed by drivers to the closest possible value
00123   // \return if successful
00124   // \see format_is_set
00125   bool set_v4l2_format(unsigned int fourcode, int width, int height,double fps=0.0);
00126 
00127   //: Return if the format is set.
00128   // Normally, a format is automatically selected of user call set_v4l2_format. User can use this function to know if a format is selected before calling start_capturing.
00129   // \see set_v4l2_format
00130   bool format_is_set() const { return fmt.fmt.pix.width!=0; }
00131 
00132   //: Get pixel format of type of compression
00133   // \return the four character code which is being used by driver(see v4l2 specification and vidl_pixel_format.h) or 0 if not set
00134   // \see set_v4l2_format
00135   unsigned int  get_v4l2_format() const {
00136                return (fmt.fmt.pix.width!=0)?
00137                       fmt.fmt.pix.pixelformat:0;
00138      }
00139 
00140   //: Return Image width in pixels.
00141   // \note You can use this function to know the width selected by driver after calling set_v4l2_format
00142   // \see set_v4l2_format
00143   int get_width() const { return fmt.fmt.pix.width; }
00144   //: Return Image height in pixels.
00145   // \note You can use this function to know the height selected by driver after calling set_v4l2_format
00146   // \see set_v4l2_format
00147   int get_height() const { return fmt.fmt.pix.height; }
00148 
00149   //: Return Current frame rate.
00150   // \see set_v4l2_format
00151   double get_frame_rate() const { return frame_rate; }
00152 
00153   // ----------------- Methods associated to controls -------------------
00154 
00155   //: Reset controls to default
00156   void reset_controls() ;
00157 
00158   //: Get number of controls
00159   // \return the number of detected controls (control not disabled and not inactive).
00160   int n_controls() const { return controls_.size(); }
00161   //: Get control
00162   // The user must downcast the pointer -depending on type- to use all funcionality.
00163   // \param i indicates the control to be extracted, from 0 to n_controls-1
00164   // \return pointer to control
00165   // \see n_controls
00166   vidl_v4l2_control * get_control(int i) const { return controls_[i]; }
00167   //: Get control from driver id
00168   // The user must downcast the pointer -depending on type- to use all funcionality.
00169   // \param id is control ID from v4l2 specification. For example, V4L2_CID_BRIGHTNESS
00170   // \return pointer to control or 0 if does not exist
00171   vidl_v4l2_control * get_control_id(int id) const
00172     { for (int i=0;i<n_controls();++i) { if (controls_[i]->id()==id) return controls_[i]; } return 0;}
00173 
00174   //: Get control from driver id
00175   // \param id is control ID from v4l2 specification. For example, V4L2_CID_BRIGHTNESS
00176   // \return pointer to control. Null if doesn't exist or is not of type V4L2_CTRL_TYPE_INTEGER
00177   vidl_v4l2_control_integer * get_control_integer_id( int id) const
00178   {
00179     vidl_v4l2_control *pc= get_control_id(id);
00180     return pc ? (pc->type()==V4L2_CTRL_TYPE_INTEGER ?
00181                  dynamic_cast<vidl_v4l2_control_integer *>(pc) : 0 ) : 0;
00182   }
00183 
00184   //: Get control from driver id
00185   // \param id is control ID from v4l2 specification. For example, V4L2_CID_BRIGHTNESS
00186   // \return pointer to control. Null if doesn't exist or is not of type V4L2_CTRL_TYPE_MENU
00187   vidl_v4l2_control_menu * get_control_menu_id( int id) const
00188   {
00189     vidl_v4l2_control *pc= get_control_id(id);
00190     return pc ? (pc->type()==V4L2_CTRL_TYPE_MENU ?
00191                  dynamic_cast<vidl_v4l2_control_menu *>(pc) : 0 ) : 0;
00192   }
00193 
00194   //: Get control from driver id
00195   // \param id is control ID from v4l2 specification. For example, V4L2_CID_BRIGHTNESS
00196   // \return pointer to control. Null if doesn't exist or is not of type V4L2_CTRL_TYPE_BOOLEAN
00197   vidl_v4l2_control_boolean * get_control_boolean_id( int id) const
00198   {
00199     vidl_v4l2_control *pc= get_control_id(id);
00200     return pc ? (pc->type()==V4L2_CTRL_TYPE_BOOLEAN ?
00201                  dynamic_cast<vidl_v4l2_control_boolean *>(pc) : 0 ) : 0;
00202   }
00203 
00204   //: Get control from driver id
00205   // \param id is control ID from v4l2 specification. For example, V4L2_CID_BRIGHTNESS
00206   // \return pointer to control. Null if doesn't exist or is not of type V4L2_CTRL_TYPE_BUTTON
00207   vidl_v4l2_control_button * get_control_button_id( int id) const
00208   {
00209     vidl_v4l2_control *pc= get_control_id(id);
00210     return pc ? (pc->type()==V4L2_CTRL_TYPE_BUTTON ?
00211                  dynamic_cast<vidl_v4l2_control_button *>(pc) : 0 ) : 0;
00212   }
00213 
00214 
00215   // ----------------- End methods associated to controls -------------------
00216 
00217   //: Start capturing
00218   // \return if successful
00219   bool start_capturing ();
00220   //: Return if device is capturing
00221   bool is_capturing() const { return capturing; }
00222   //: Stop capturing
00223   // \return if successful
00224   bool stop_capturing();
00225   //: Read next frame
00226   // \return if successful
00227   bool read_frame();
00228 
00229 
00230   // ----------------- Methods associated to buffers -------------------
00231 
00232   //: Set numbers of buffers
00233   // \return if successful
00234   bool set_number_of_buffers(unsigned int nb);
00235   //: Get numbers of buffers
00236   unsigned int get_number_of_buffers() const { return pre_nbuffers; }
00237 
00238   //: Return the last used buffer
00239   // \pre device is capturing
00240   void * current_buffer() const {
00241     return (last_buffer==-1)?0:buffers[last_buffer].start;
00242   }
00243 
00244   //: Return length of the last used buffer
00245   // \pre device is capturing
00246   unsigned int current_buffer_length() const { // return __u32
00247     return (last_buffer==-1)?0:buffers[last_buffer].buf.length;
00248   }
00249 
00250   //: Return buffer number i
00251   // \pre device is capturing
00252   // \see get_number_of_buffers
00253   void *ibuffer(unsigned int i) const {
00254     return buffers && i < n_buffers ? buffers[i].start : 0;
00255   }
00256 
00257   // Return number in sequence associated to last frame, as indicated by driver
00258   unsigned int sequence() const { // return __u32
00259     if (last_buffer==-1) vcl_cerr << "UPS\n";
00260     return (last_buffer==-1)?0:buffers[last_buffer].buf.sequence;
00261   }
00262 
00263   // ----------------- End methods associated to buffers -------------------
00264 
00265 
00266   //: Return if driver has time associated to the captured frame
00267   // \pre device is capturing
00268   bool time_available() const {
00269     return (last_buffer==-1)?false:(buffers[last_buffer].buf.flags&V4L2_BUF_FLAG_TIMECODE);
00270   }
00271 
00272   //: Time from last frame
00273   // \see time_available
00274   v4l2_timecode time() const {
00275     return (last_buffer==-1)?v4l2_timecode():buffers[last_buffer].buf.timecode;
00276   }
00277 
00278   // --------   Next functions indicate if the device is in a bad state: not usable.
00279 
00280   //: Cast to bool is true if video device is working ok
00281   operator safe_bool () const
00282   { return (last_error.size()==0)? VCL_SAFE_BOOL_TRUE : 0; }
00283 
00284   //: Return false if video device is not working ok
00285   bool operator!() const
00286   { return (last_error.size()==0)? false : true; }
00287 
00288   //: Return last error if device is in a bad state. Empty if ok
00289   vcl_string get_error() const { return last_error; }
00290 
00291 
00292   //-------------------------------------------------------
00293   // reference counting if used through sptr
00294  public:
00295 
00296   //: Increment reference count
00297   void ref() { ref_count_++; }
00298 
00299   //: Decrement reference count
00300   void unref(){
00301     assert (ref_count_ >0);
00302     ref_count_--;
00303     if (ref_count_==0)
00304     {
00305       delete this;
00306     }
00307   }
00308 
00309   //: Number of objects referring to this data
00310   int ref_count() const { return ref_count_; }
00311 
00312  private:
00313   int ref_count_;
00314 };
00315 
00316 
00317 vcl_ostream &
00318 operator << (vcl_ostream &os, const vidl_v4l2_device & dev);
00319 
00320 
00321 #endif // vidl_v4l2_device_h_

Generated on Mon Mar 8 05:10:35 2010 for core/vidl by  doxygen 1.5.1