CVD 0.8
cvd/diskbuffer2.h
00001 /*                       
00002     This file is part of the CVD Library.
00003 
00004     Copyright (C) 2005 The Authors
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Lesser General Public
00008     License as published by the Free Software Foundation; either
00009     version 2.1 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Lesser General Public License for more details.
00015 
00016     You should have received a copy of the GNU Lesser General Public
00017     License along with this library; if not, write to the Free Software
00018     Foundation, Inc., 
00019     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020 */
00021 #ifndef CVD_DISKBUFFER2_H
00022 #define CVD_DISKBUFFER2_H
00023 
00024 #include <vector>
00025 #include <string>
00026 #include <fstream>
00027 #include <errno.h>
00028 
00029 #include <cvd/localvideobuffer.h>
00030 #include <cvd/videobufferflags.h>
00031 #include <cvd/diskbuffer2_frame.h>
00032 #include <cvd/image_io.h>
00033 #include <cvd/config.h>
00034 
00035 namespace CVD
00036 {
00037     //
00038     // GLOBLIST
00044     #ifdef CVD_HAVE_GLOB
00045     std::vector<std::string> globlist(const std::string& gl);
00046     #endif
00047 
00048     namespace Exceptions
00049     {
00052         namespace DiskBuffer2
00053         {
00056             struct All: public CVD::Exceptions::VideoBuffer::All { };
00059             struct NoFiles: public All { NoFiles(); };
00062             struct BadFile: public All { BadFile(const std::string&, int); 
00063             }; 
00066             struct BadImage: public All { BadImage(const std::string& file, const std::string& error); 
00067             };
00070             struct BadImageSize: public All { BadImageSize(const std::string& file); 
00071             };
00074             struct EndOfBuffer: public All { EndOfBuffer(); };
00077             struct BadSeek: public All { BadSeek(double t);
00078              }; 
00079             
00080         }
00081     }
00082 
00090     template<typename T> 
00091     class DiskBuffer2: public CVD::LocalVideoBuffer<T>
00092     {
00093         public:
00100             DiskBuffer2(const std::vector<std::string>& names, double fps, VideoBufferFlags::OnEndOfBuffer eob = VideoBufferFlags::RepeatLastFrame);
00101 
00102             virtual ImageRef size() {return my_size;}
00103             
00107             virtual bool frame_pending() {return frame_ready;}
00108 
00109             virtual DiskBuffer2Frame<T>* get_frame();
00110             virtual void put_frame(VideoFrame<T>* f);
00111             virtual void seek_to(double t);
00112         
00115             virtual void on_end_of_buffer(VideoBufferFlags::OnEndOfBuffer eob) 
00116                 {end_of_buffer_behaviour = eob;}
00117 
00118             virtual double frame_rate() 
00119             {
00120                 return frames_per_sec;
00121             }
00122 
00123         protected:
00124             ImageRef my_size;
00125             int      next_frame;
00126             double   start_time;
00127             double   time_per_frame, frames_per_sec;
00128             bool frame_ready;
00129             std::vector<std::string> file_names;
00130             VideoBufferFlags::OnEndOfBuffer end_of_buffer_behaviour;
00131     };
00132 
00133     //
00134     // CONSTRUCTOR
00135     //
00136     template<typename T>
00137     inline DiskBuffer2<T>::DiskBuffer2(const std::vector<std::string>& names, double fps, VideoBufferFlags::OnEndOfBuffer eob) 
00138     :LocalVideoBuffer<T>(VideoBufferType::NotLive),end_of_buffer_behaviour(eob)
00139     {
00140         frames_per_sec = fps;
00141 
00142         start_time = 0;
00143         next_frame=0;
00144         time_per_frame = 1/fps; 
00145 
00146         file_names = names;
00147 
00148         if(file_names.size() == 0)
00149             throw Exceptions::DiskBuffer2::NoFiles();
00150 
00151         Image<T> foo;
00152         std::ifstream im;
00153         im.open(names[0].c_str(), std::ios::in|std::ios::binary);
00154 
00155         if(!im.good())
00156             throw Exceptions::DiskBuffer2::BadFile(names[0], errno);
00157         
00158         try
00159         {
00160             img_load(foo, im);
00161         }
00162         catch(Exceptions::Image_IO::All err)
00163         {
00164             throw Exceptions::DiskBuffer2::BadImage(names[0], err.what);
00165         }
00166 
00167         my_size = foo.size();
00168         frame_ready = true;
00169     }
00170 
00171     //
00172     // GET FRAME
00173     //
00174     template<typename T>
00175     inline DiskBuffer2Frame<T>* DiskBuffer2<T>::get_frame()
00176     {
00177         if(next_frame < 0)
00178             next_frame = 0;
00179 
00180         if(!frame_pending())
00181             throw Exceptions::DiskBuffer2::EndOfBuffer();
00182 
00183         Image<T> foo(my_size);
00184         
00185         std::ifstream im_file(file_names[next_frame].c_str(), std::ios::in|std::ios::binary);
00186 
00187         if(!im_file.good())
00188             throw Exceptions::DiskBuffer2::BadFile(file_names[next_frame], errno);
00189 
00190         try{
00191           img_load(foo, im_file);
00192         }
00193         catch(CVD::Exceptions::Image_IO::All err)
00194         {
00195             throw Exceptions::DiskBuffer2::BadImage(file_names[next_frame], err.what);
00196         }
00197 
00198         DiskBuffer2Frame<T>* vf = new DiskBuffer2Frame<T>(next_frame * time_per_frame + start_time, foo, file_names[next_frame]);
00199 
00200         next_frame++;
00201         
00202         if(next_frame > (int)file_names.size()-1)
00203         {
00204             switch(end_of_buffer_behaviour)
00205             {
00206                 case VideoBufferFlags::RepeatLastFrame:
00207                     next_frame = file_names.size()-1;
00208                     break;
00209                 
00210                 case VideoBufferFlags::UnsetPending:
00211                     frame_ready = false;
00212                    break;
00213                 
00214                 case VideoBufferFlags::Loop:
00215                     next_frame = 0;
00216                     break;
00217             }
00218         }
00219 
00220         return vf;  
00221     }
00222 
00223     //
00224     // PUT FRAME
00225     //
00226     template<typename T>
00227     inline void DiskBuffer2<T>::put_frame(VideoFrame<T>* f)
00228     {
00229         //Check that the type is correct...
00230         DiskBuffer2Frame<T>* db2f = dynamic_cast<DiskBuffer2Frame<T>*>(f);
00231 
00232         if(db2f == NULL)
00233             throw CVD::Exceptions::VideoBuffer::BadPutFrame();
00234         else 
00235             delete db2f;
00236     }
00237 
00238     //
00239     // SEEK TO
00240     //
00241     template<typename T>
00242     inline void DiskBuffer2<T>::seek_to(double t)
00243     {
00244         // t is in ms, but work in seconds
00245         // round the answer to the nearest whole frame
00246         int frameno = static_cast<int>((t - start_time) / time_per_frame + 0.5);
00247         if(frameno < 0 || static_cast<unsigned int>(frameno) > (file_names.size() - 1))
00248             throw Exceptions::DiskBuffer2::BadSeek(t);
00249         next_frame = frameno;
00250         frame_ready = true;
00251     }
00252 }
00253 
00254 
00255 #endif