CVD 0.8
cvd/videosource.h
00001 #ifndef VIDEOSOURCE_H
00002 #define VIDEOSOURCE_H
00003 
00004 #include <iostream>
00005 #include <fstream>
00006 #include <sstream>
00007 #include <string>
00008 #include <vector>
00009 #include <cstdlib>
00010 
00011 #include <cvd/config.h>
00012 
00013 #include <cvd/colourspacebuffer.h>
00014 #include <cvd/deinterlacebuffer.h>
00015 #include <cvd/colourspaces.h>
00016 #include <cvd/videobufferwithdata.h>
00017 #include <cvd/readaheadvideobuffer.h>
00018 
00019 #include <cvd/diskbuffer2.h>
00020 #include <cvd/serverpushjpegbuffer.h>
00021 
00022 namespace CVD {
00023     struct ParseException : public Exceptions::All
00024     {
00025         ParseException(const std::string& what_) { what = what_; }
00026     };
00027     
00028     struct VideoSourceException : public Exceptions::All
00029     {
00030         VideoSourceException(const std::string& what_) { what = what_; }
00031     };
00032 
00033     struct VideoSource 
00034     {
00035         std::string protocol;
00036         std::string identifier;
00037         typedef std::vector<std::pair<std::string,std::string> > option_list;
00038         option_list options;
00039     };
00040 
00041     std::ostream& operator<<(std::ostream& out, const VideoSource& vs);
00042 
00043     void parse(std::istream& in, VideoSource& vs);
00044     template <class T> VideoBuffer<T>* open_video_source(const std::string& src);
00045 
00047     //
00048     // Server push JPEG buffer
00049     //
00050 
00051     template<class T, bool Implemented = Pixel::DefaultConvertible<T>::is> struct makeJPEGStream
00052     {
00053         static VideoBuffer<T>* make(const std::string& filename)
00054         {
00055             using std::auto_ptr;
00056             using std::ifstream;
00057 
00058             auto_ptr<std::ifstream> stream(new ifstream(filename.c_str()));
00059             
00060             auto_ptr<VideoBuffer<T> > buf(static_cast<VideoBuffer<T>*>(new ServerPushJpegBuffer<T>(*stream)));
00061             return new VideoBufferWithData<T, std::ifstream>(buf, stream);
00062         }
00063     };
00064 
00065     template<class T> struct makeJPEGStream<T, false>
00066     {
00067         static VideoBuffer<T>* make(const std::string&)
00068         {
00069             throw VideoSourceException("ServerPushJpegBuffer cannot handle type " + PNM::type_name<T>::name());
00070         }
00071     };
00072 
00073     void get_jpegstream_options(const VideoSource& vs, int& fps);
00074 
00075 
00077     //
00078     // Deinterlace buffer
00079     //
00080     void get_deinterlace_options(const VideoSource& vs, DeinterlaceBufferFields::Fields& fields, bool&);
00081 
00082     
00083     namespace Internal{
00084         template<class T> struct CanDeinterlace
00085         {
00086             static const bool can = std::numeric_limits<T>::is_specialized;
00087         };
00088 
00089         template<class T> struct CanDeinterlace<Rgb<T> >
00090         {
00091             static const bool can = CanDeinterlace<T>::can;
00092         };
00093     };
00094 
00095     template<class T,  bool B = Internal::CanDeinterlace<T>::can> struct makeDeinterlaceBuffer
00096     {
00097         static VideoBuffer<T>* make(DeinterlaceBufferFields::Fields f, bool& linedouble, const std::string& url)
00098         {
00099             std::auto_ptr<VideoBuffer<T> > source  = std::auto_ptr<VideoBuffer<T> > (static_cast<VideoBuffer<T>*>(open_video_source<T>(url)));
00100             std::auto_ptr<VideoBuffer<T> > de_int  = std::auto_ptr<VideoBuffer<T> > (static_cast<DeinterlaceBuffer<T>*>(new DeinterlaceBuffer<T>(*source, f, linedouble)));
00101             return new VideoBufferWithData<T, VideoBuffer<T> >(de_int, source);
00102         }
00103     };
00104 
00105     template<class T> struct makeDeinterlaceBuffer<T, 0>
00106     {
00107         static VideoBuffer<T>* make(DeinterlaceBufferFields::Fields, bool&, const std::string&)
00108         {
00109             throw  VideoSourceException("DeinterlaceBuffer cannot handle input type");
00110         }
00111     };
00113     //
00114     // Colourspace conversion buffer
00115     //
00116     
00117     void get_colourspace_options(const VideoSource& vs, std::string& from);
00118 
00119     template<class Out, class In, bool can_convert> struct MakeConverter{
00120         static VideoBuffer<Out>* make(const std::string& r)
00121         {
00122             std::auto_ptr<VideoBuffer<In> > buf  = std::auto_ptr<VideoBuffer<In> > (static_cast<VideoBuffer<In>*>(open_video_source<In>(r)));
00123             std::auto_ptr<VideoBuffer<Out> > cvt = std::auto_ptr<VideoBuffer<Out> >(static_cast<VideoBuffer<Out>*>( new ColourspaceBuffer<Out, In>(*buf)));
00124             return new VideoBufferWithData<Out, VideoBuffer<In> >(cvt, buf);
00125         }
00126     };
00127 
00128     template<class Out, class In> struct MakeConverter<Out, In, false>
00129     {
00130         static VideoBuffer<Out>* make(const std::string&)
00131         {
00132             throw VideoSourceException("ColorspaceBuffer cannot convert from " + PNM::type_name<In>::name() + " to " + PNM::type_name<Out>::name());
00133         }
00134     };
00135 
00136     template<class T> struct MakeConverter<T, T, true>{
00137         static VideoBuffer<T>* make(const std::string& r)
00138         {
00139             return open_video_source<T>(r);
00140         }
00141     };
00142 
00143     template<class Out, class In> VideoBuffer<Out>* makeConvertBufferBit(const std::string& r)
00144     {
00145         return MakeConverter<Out, In, IsConvertible<In, Out>::is >::make(r);
00146     };
00147 
00148     template<class T> VideoBuffer<T>* makeColourspaceBuffer(const std::string& c, const std::string& r)
00149     {
00150 
00151         if(c == "byte" || c == "mono" || c == "gray" || c == "grey")
00152             return makeConvertBufferBit<T, byte>(r);
00153         else if(c == "rgb<byte>" || c == "rgb")
00154             return makeConvertBufferBit<T, Rgb<byte> >(r);
00155         else if(c == "yuv411")
00156             return makeConvertBufferBit<T, yuv411>(r);
00157         else if(c == "yuv422")
00158             return makeConvertBufferBit<T, yuv422>(r);
00159         else if(c == "yuv420p")
00160             return makeConvertBufferBit<T, yuv420p>(r);
00161         else if(c == "vuy422")
00162             return makeConvertBufferBit<T, vuy422>(r);
00163         else if(c == "bayer_bggr")
00164             return makeConvertBufferBit<T, bayer_bggr>(r);
00165         else if(c == "bayer_gbrg")
00166             return makeConvertBufferBit<T, bayer_gbrg>(r);
00167         else if(c == "bayer_grbg")
00168             return makeConvertBufferBit<T, bayer_grbg>(r);
00169         else if(c == "bayer_rggb")
00170             return makeConvertBufferBit<T, bayer_rggb>(r);
00171         else if(c == "bayer_bggr16be")
00172             return makeConvertBufferBit<T, bayer_bggr16be>(r);
00173         else if(c == "bayer_gbrg16be")
00174             return makeConvertBufferBit<T, bayer_gbrg16be>(r);
00175         else if(c == "bayer_grbg16be")
00176             return makeConvertBufferBit<T, bayer_grbg16be>(r);
00177         else if(c == "bayer_rggb16be")
00178             return makeConvertBufferBit<T, bayer_rggb16be>(r);
00179         else
00180             throw  VideoSourceException("ColorspaceBuffer cannot handle type " + c);
00181     }
00182 
00184     //
00185     // DiskBuffer2 buffer
00186     //
00187 
00188     // This has to be done with conditional compilation.
00189 
00190 
00191 #ifdef CVD_HAVE_GLOB
00192     template<class T, bool Implemented = Pixel::DefaultConvertible<T>::is> struct makeDiskBuffer2
00193     {
00194         static VideoBuffer<T>* make(const std::string& files, double fps, VideoBufferFlags::OnEndOfBuffer eob)
00195         {
00196             return new DiskBuffer2<T>(globlist(files), fps, eob);    
00197         }
00198     };
00199 
00200     template<class T> struct makeDiskBuffer2<T, false>
00201     {
00202         static VideoBuffer<T>* make(const std::string& , double , VideoBufferFlags::OnEndOfBuffer)
00203         {
00204             throw VideoSourceException("DiskBuffer2 cannot handle type " + PNM::type_name<T>::name());
00205         }
00206     };
00207 
00208 #else
00209     template<class T, bool Implemented = 0> struct makeDiskBuffer2
00210     {
00211         static VideoBuffer<T>* make(const std::string& , double , VideoBufferFlags::OnEndOfBuffer)
00212         {
00213             throw VideoSourceException("DiskBuffer2 (shell glob expansion) is not compiled in to libcvd.");
00214         }
00215     };
00216 #endif
00217 
00218     void get_files_options(const VideoSource& vs, int& fps, int& ra_frames, VideoBufferFlags::OnEndOfBuffer& eob);
00219     
00221     //
00222     // v4l1 buffer
00223     //
00224 
00225     template <class T> VideoBuffer<T>* makeV4L1Buffer(const std::string&, const ImageRef& )
00226     {
00227         throw VideoSourceException("V4L1Buffer cannot handle types other than byte, bayer, yuv422, Rgb<byte>");
00228     }
00229 
00230     template <> VideoBuffer<byte>* makeV4L1Buffer(const std::string& dev, const ImageRef& size);
00231     template <> VideoBuffer<bayer>* makeV4L1Buffer(const std::string& dev, const ImageRef& size);
00232     template <> VideoBuffer<yuv422>* makeV4L1Buffer(const std::string& dev, const ImageRef& size);
00233     template <> VideoBuffer<Rgb<byte> >* makeV4L1Buffer(const std::string& dev, const ImageRef& size);
00234 
00235     void get_v4l1_options(const VideoSource& vs, ImageRef& size);
00236 
00238     //
00239     // v4l buffer
00240     //
00241 
00242     template <class T> VideoBuffer<T>* makeV4LBuffer(const std::string&, const ImageRef&, int, bool, bool)
00243     {
00244         throw VideoSourceException("V4LBuffer cannot handle types other than byte, bayer, yuv422, vuy422, Rgb<byte>");
00245     }
00246 
00247     template <> VideoBuffer<byte>* makeV4LBuffer(const std::string& dev, const ImageRef& size, int input, bool interlaced, bool verbose);
00248     template <> VideoBuffer<bayer_grbg>* makeV4LBuffer(const std::string& dev, const ImageRef& size, int input, bool interlaced, bool verbose);
00249     template <> VideoBuffer<yuv422>* makeV4LBuffer(const std::string& dev, const ImageRef& size, int input, bool interlaced, bool verbose);
00250     template <> VideoBuffer<vuy422>* makeV4LBuffer(const std::string& dev, const ImageRef& size, int input, bool interlaced, bool verbose);
00251     template <> VideoBuffer<Rgb<byte> >* makeV4LBuffer(const std::string& dev, const ImageRef& size, int input, bool interlaced, bool verbose);
00252     template <> VideoBuffer<Rgb8>* makeV4LBuffer(const std::string& dev, const ImageRef& size, int input, bool interlaced, bool verbose);
00253 
00254     void get_v4l2_options(const VideoSource& vs, ImageRef& size, int& input, bool& interlaced, bool& verbose);
00255 
00256 
00258     //
00259     // video file buffer
00260     //
00261 
00262     template <class T> VideoBuffer<T>* makeVideoFileBuffer(const std::string& , VideoBufferFlags::OnEndOfBuffer )
00263     {
00264         throw VideoSourceException("VideoFileBuffer cannot handle types other than byte, Rgb<byte>");
00265     }
00266     
00267     template <> VideoBuffer<byte>* makeVideoFileBuffer(const std::string& file, VideoBufferFlags::OnEndOfBuffer eob);
00268     template <> VideoBuffer<Rgb<byte> >* makeVideoFileBuffer(const std::string& file, VideoBufferFlags::OnEndOfBuffer eob);
00269 
00270     void get_file_options(const VideoSource& vs, int& ra_frames, VideoBufferFlags::OnEndOfBuffer& eob);
00271 
00273     //
00274     // DC1394 buffer
00275     //
00276     template <class T> VideoBuffer<T>* makeDVBuffer2(int , ImageRef , float , ImageRef, bool, bool, int)
00277     {
00278         throw VideoSourceException("DVBuffer2 cannot handle " + PNM::type_name<T>::name());
00279     }
00280     
00281     template <> VideoBuffer<byte>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00282     template <> VideoBuffer<unsigned short>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00283     template <> VideoBuffer<yuv411>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00284     template <> VideoBuffer<yuv422>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00285     template <> VideoBuffer<Rgb<byte> >* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00286     template <> VideoBuffer<bayer_bggr>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00287     template <> VideoBuffer<bayer_gbrg>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00288     template <> VideoBuffer<bayer_grbg>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00289     template <> VideoBuffer<bayer_rggb>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00290     template <> VideoBuffer<bayer_bggr16be>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00291     template <> VideoBuffer<bayer_gbrg16be>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00292     template <> VideoBuffer<bayer_grbg16be>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00293     template <> VideoBuffer<bayer_rggb16be>* makeDVBuffer2(int cam, ImageRef size, float fps, ImageRef offset, bool verbose, bool bus_reset, int format7_mode);
00294 
00295     void get_dc1394_options(const VideoSource& vs, ImageRef& size, float& fps, ImageRef& offset, bool& verbose, bool& bus_reset, int& format7_mode);
00296 
00298     //
00299     // QuickTime buffer
00300     //
00301 
00302     template <class T> VideoBuffer<T> * makeQTBuffer( const ImageRef & , int , bool, bool )
00303     {
00304         throw VideoSourceException("QTBuffer cannot handle " + PNM::type_name<T>::name());
00305     }
00306     template <> VideoBuffer<vuy422> * makeQTBuffer( const ImageRef & size, int input, bool showsettings, bool verbose);
00307     template <> VideoBuffer<yuv422> * makeQTBuffer( const ImageRef & size, int input, bool showsettings, bool verbose);
00308     template <> VideoBuffer<Rgb<byte> > * makeQTBuffer( const ImageRef & size, int input, bool showsettings, bool verbose);
00309     
00310     void get_qt_options(const VideoSource & vs, ImageRef & size, bool & showsettings, bool & verbose);
00311 
00312 
00314     //
00315     // video source handler
00316     //
00317 
00318     template <class T> VideoBuffer<T>* open_video_source(const VideoSource& vs)
00319     {
00320         using std::auto_ptr;
00321         if(vs.protocol == "jpegstream")
00322         {
00323             int ra_frames=0;
00324             get_jpegstream_options(vs, ra_frames);
00325 
00326             auto_ptr<VideoBuffer<T> > jpeg_buffer(makeJPEGStream<T>::make(vs.identifier));
00327 
00328             if(ra_frames == 0)
00329                 return jpeg_buffer.release();
00330             else
00331             {
00332                 auto_ptr<VideoBuffer<T> > b(new ReadAheadVideoBuffer<T>(*(jpeg_buffer.get()), ra_frames));
00333                 return new VideoBufferWithData<T, VideoBuffer<T> >(b, jpeg_buffer);
00334             }
00335         }
00336         else if(vs.protocol == "deinterlace")
00337         {
00338             DeinterlaceBufferFields::Fields f=DeinterlaceBufferFields::OddEven;
00339             bool linedouble=false;
00340 
00341             get_deinterlace_options(vs, f, linedouble);
00342 
00343             return makeDeinterlaceBuffer<T>::make(f, linedouble, vs.identifier);
00344         }
00345         else if(vs.protocol == "colourspace")
00346         {
00347             std::string from = "byte";
00348             get_colourspace_options(vs, from);
00349 
00350             return makeColourspaceBuffer<T>(from, vs.identifier);
00351         }
00352         else if (vs.protocol == "files") {
00353             int fps, ra_frames=0;
00354             VideoBufferFlags::OnEndOfBuffer eob;
00355             get_files_options(vs, fps, ra_frames, eob);
00356             VideoBuffer<T>* vb = makeDiskBuffer2<T>::make(vs.identifier, fps, eob);
00357             if (ra_frames)
00358                 vb = new ReadAheadVideoBuffer<T>(*vb, ra_frames);
00359             return vb;
00360         }
00361         else if (vs.protocol == "v4l1") {
00362             ImageRef size;
00363             get_v4l1_options(vs, size);
00364             return makeV4L1Buffer<T>(vs.identifier, size);
00365         } 
00366         else if (vs.protocol == "v4l2") {
00367             ImageRef size;
00368             int input;
00369             bool interlaced, verbose;
00370             get_v4l2_options(vs, size, input, interlaced, verbose);
00371             return makeV4LBuffer<T>(vs.identifier, size, input, interlaced, verbose);   
00372         } 
00373         else if (vs.protocol == "dc1394") {
00374             int cam_no = atoi(vs.identifier.c_str());
00375             ImageRef size, offset;
00376             float fps;
00377             bool verbose;
00378             bool bus_reset;
00379             int  format7_mode;
00380             get_dc1394_options(vs, size, fps, offset, verbose, bus_reset, format7_mode);
00381             return makeDVBuffer2<T>(cam_no, size, fps, offset, verbose, bus_reset, format7_mode);
00382         } 
00383         else if (vs.protocol == "file") {
00384             int ra_frames = 0;
00385             VideoBufferFlags::OnEndOfBuffer eob;
00386             get_file_options(vs, ra_frames, eob);
00387             VideoBuffer<T>* vb = makeVideoFileBuffer<T>(vs.identifier, eob);
00388             if (ra_frames)
00389                 vb = new ReadAheadVideoBuffer<T>(*vb, ra_frames);
00390             return vb;
00391         } 
00392     else if (vs.protocol == "qt") {
00393         ImageRef size;
00394         bool showsettings, verbose;
00395         int input = atoi(vs.identifier.c_str());
00396         get_qt_options(vs, size, showsettings, verbose);
00397         return makeQTBuffer<T>(size, input, showsettings, verbose);
00398     }
00399         else
00400             throw VideoSourceException("undefined video source protocol: '" + vs.protocol + "'\n\t valid protocols: "
00401                                        "colourspace, jpegstream, "
00402                                        "file, "
00403                                        "v4l2, "
00404                                        "v4l1, "
00405                                        "dc1394, "
00406                                        "qt, "
00407                                        "files"
00408                                        );
00409     }
00410 
00417     template <class T> VideoBuffer<T>* open_video_source(std::istream& in)
00418     {
00419         VideoSource vs;
00420         parse(in, vs);
00421         return open_video_source<T>(vs);
00422     }
00423 
00561     template <class T> VideoBuffer<T>* open_video_source(const std::string& src)
00562     {
00563         std::istringstream in(src);
00564         return open_video_source<T>(in);
00565     }    
00566 }
00567 
00568 #endif