CVD 0.8
cvd/deinterlacebuffer.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 // PAS 17/6/04 (revised 16/2/05)
00022 #ifndef CVD_INCLUDE_DEINTERLACEBUFFER_H
00023 #define CVD_INCLUDE_DEINTERLACEBUFFER_H
00024 
00025 #include <cvd/videobuffer.h>
00026 #include <cvd/deinterlaceframe.h>
00027 
00028 namespace CVD
00029 {
00031 // DEINTERLACE BUFFER EXCEPTIONS
00032 //
00033 namespace Exceptions
00034 {
00037     namespace DeinterlaceBuffer
00038     {   
00041         struct All: public CVD::Exceptions::VideoBuffer::All { }; 
00042         
00045         struct OddNumberOfLines: public All { OddNumberOfLines(); }; 
00046     }
00047 }
00048 
00049 
00051 // DEINTERLACE BUFFER
00052 //
00053 
00075 
00077 struct DeinterlaceBufferFields
00078 {
00079     enum Fields{
00080         OddOnly, 
00081         EvenOnly, 
00082         OddEven, 
00083         EvenOdd 
00084     }; 
00085 };
00086 
00087 template <typename T>
00088 class DeinterlaceBuffer : public VideoBuffer<T>
00089 {
00090     public:
00091         typedef DeinterlaceBufferFields Fields;
00095         DeinterlaceBuffer(CVD::VideoBuffer<T>& buf, Fields::Fields fields = Fields::OddEven, bool line_double=false);
00096  
00099         ImageRef size();
00100         
00101         CVD::VideoFrame<T>* get_frame();
00102         
00103         void put_frame(CVD::VideoFrame<T>* f);
00104         
00105         virtual bool frame_pending()
00106             {return m_vidbuf.frame_pending();}
00107             
00108         virtual void seek_to(double t)
00109             {return m_vidbuf.seek_to(t);}
00110             
00114         virtual double frame_rate()
00115         {
00116             if(m_fields == Fields::OddOnly || m_fields == Fields::EvenOnly)
00117                 return m_vidbuf.frame_rate();
00118             else
00119                 return m_vidbuf.frame_rate() * 2.0;
00120         }
00121       
00122    private:
00123         CVD::VideoFrame<T>* my_realframe;
00124         CVD::VideoBuffer<T>& m_vidbuf;
00125         Fields::Fields m_fields;
00126         bool m_loadnewframe;
00127         ImageRef m_size;
00128         unsigned int m_linebytes;
00129         bool line_double;
00130 };
00131 
00132 //
00133 // CONSTRUCTOR
00134 //
00135 template <typename T>
00136 DeinterlaceBuffer<T>::DeinterlaceBuffer(CVD::VideoBuffer<T>& vidbuf, Fields::Fields fields, bool l) :
00137     VideoBuffer<T>(vidbuf.type()),
00138     m_vidbuf(vidbuf),
00139     m_fields(fields),
00140     m_loadnewframe(true),
00141     line_double(l)
00142 {
00143     // Check it has an even number of lines
00144     if(m_vidbuf.size().y % 2 != 0)
00145         throw Exceptions::DeinterlaceBuffer::OddNumberOfLines();
00146     
00147     if(line_double == false)
00148         m_size = ImageRef(m_vidbuf.size().x, m_vidbuf.size().y / 2);
00149     else
00150         m_size = m_vidbuf.size();
00151 
00152     m_linebytes = sizeof(T) * m_size.x;
00153 }
00154 
00155 //
00156 // GET FRAME
00157 //
00158 template <typename T>
00159 VideoFrame<T>* DeinterlaceBuffer<T>::get_frame()
00160 {
00161     if(m_loadnewframe)
00162     {
00163         // Get a new frame from the real videobuffer
00164         my_realframe = m_vidbuf.get_frame();
00165     }
00166         
00167     // Now return the deinterlaced image
00168     // First sort out the time
00169     double time = my_realframe->timestamp();
00170     
00171     // If we're giving the second frame of a pair, make its time half-way to the next frame
00172     if(!m_loadnewframe)
00173         time += frame_rate(); 
00174     
00175     Image<T> im(size());
00176     DeinterlaceFrame<T>* frame = new DeinterlaceFrame<T>(time, im);
00177 
00178 
00179     if(m_fields == Fields::OddOnly || 
00180         (m_fields == Fields::OddEven && m_loadnewframe) ||
00181         (m_fields == Fields::EvenOdd && !m_loadnewframe))
00182     {
00183 
00184         // We want the odd field
00185         if(line_double)
00186         {
00187             //Copy line 0 from line 1, and copy over line 1 to line 1
00188             for(int y=0; y < 2; y++)
00189                 for(int x=0; x < m_size.x; x++)
00190                     (*frame)[y][x] = (*my_realframe)[0][x];
00191 
00192             //Done 0, 1. next 2, 3
00193 
00194             for(int y=3; y < m_size.y; y+=2)
00195                 for(int x=0; x < m_size.x; x++)
00196                 {
00197                     (*frame)[y][x] = (*my_realframe)[y][x];
00198                     (*frame)[y-1][x] = ((*my_realframe)[y][x] + (*my_realframe)[y-2][x])/2;
00199                 }
00200         }
00201         else
00202         {
00203             for(int y=0; y < m_size.y; y++)
00204                 for(int x=0; x < m_size.x; x++)
00205                     (*frame)[y][x] = (*my_realframe)[2*y+1][x];
00206         }
00207         
00208     }
00209     else
00210     {
00211         // We want the even field
00212         // We want the odd field
00213         if(line_double)
00214         {
00215             //Copy over and double the first set of lines
00216             for(int y=0; y < m_size.y-2; y+=2)
00217                 for(int x=0; x < m_size.x; x++)
00218                 {
00219                     (*frame)[y][x] = (*my_realframe)[y][x];
00220                     (*frame)[y+1][x] = ((*my_realframe)[y][x] + (*my_realframe)[y+2][x])/2;
00221                 }
00222             
00223             //Copy the last line.
00224             for(int y=m_size.y-2; y < m_size.y; y++)
00225                 for(int x=0; x < m_size.x; x++)
00226                     (*frame)[y][x] = (*my_realframe)[m_size.y-2][x];
00227         }
00228         else
00229         {
00230             for(int y=0; y < m_size.y; y++)
00231                 for(int x=0; x < m_size.x; x++)
00232                     (*frame)[y][x] = (*my_realframe)[2*y][x];
00233         }
00234     }
00235     frame->real_frame = my_realframe;
00236     
00237     if(m_fields == Fields::OddEven || m_fields == Fields::EvenOdd)
00238     {
00239         // If we're taking both fields, we only load a frame every other field
00240         m_loadnewframe = !m_loadnewframe;
00241     }
00242 
00243   return frame;
00244 }
00245 
00246 //
00247 // SIZE
00248 //
00249 template <typename T>
00250 ImageRef DeinterlaceBuffer<T>::size()
00251 {
00252     return m_size;
00253 }
00254 
00255 //
00256 // PUT FRAME
00257 //
00258 template <typename T>
00259 void DeinterlaceBuffer<T>::put_frame(CVD::VideoFrame<T>* frame)
00260 {
00261     if(m_loadnewframe)
00262     {
00263         // Next time we'll be getting a new real frame, so put back the current real frame
00264         m_vidbuf.put_frame(my_realframe);
00265     }
00266     
00267     // And delete the data for my current deinterlaced frame
00268     delete dynamic_cast<DeinterlaceFrame<T>*>(frame);
00269 }
00270 
00271 } // CVD
00272 #endif