libcvd-members
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libcvd-members] libcvd cvd/videofilebuffer.h cvd_src/thread.cpp... [vid


From: Edward Rosten
Subject: [Libcvd-members] libcvd cvd/videofilebuffer.h cvd_src/thread.cpp... [videofilebuffer_test_23052006]
Date: Tue, 23 May 2006 23:41:33 +0000

CVSROOT:        /cvsroot/libcvd
Module name:    libcvd
Branch:         videofilebuffer_test_23052006
Changes by:     Edward Rosten <address@hidden>  06/05/23 23:41:33

Modified files:
        cvd            : videofilebuffer.h 
        cvd_src        : thread.cpp videofilebuffer.cc 

Log message:
        Changes to cause Rgb<byte> images to be deallocated as Rgb<byte>
        images, not byte images.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/libcvd/libcvd/cvd/videofilebuffer.h.diff?only_with_tag=videofilebuffer_test_23052006&tr1=1.11&tr2=1.11.2.1&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/libcvd/libcvd/cvd_src/thread.cpp.diff?only_with_tag=videofilebuffer_test_23052006&tr1=1.2&tr2=1.2.2.1&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/libcvd/libcvd/cvd_src/videofilebuffer.cc.diff?only_with_tag=videofilebuffer_test_23052006&tr1=1.9&tr2=1.9.2.1&r1=text&r2=text

Patches:
Index: libcvd/cvd/videofilebuffer.h
diff -u /dev/null libcvd/cvd/videofilebuffer.h:1.11.2.1
--- /dev/null   Tue May 23 23:41:33 2006
+++ libcvd/cvd/videofilebuffer.h        Tue May 23 23:41:33 2006
@@ -0,0 +1,268 @@
+/*                       
+       This file is part of the CVD Library.
+
+       Copyright (C) 2005 The Authors
+
+       This library is free software; you can redistribute it and/or
+       modify it under the terms of the GNU Lesser General Public
+       License as published by the Free Software Foundation; either
+       version 2.1 of the License, or (at your option) any later version.
+
+       This library is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+       Lesser General Public License for more details.
+
+       You should have received a copy of the GNU Lesser General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef CVD_VIDEOFILEBUFFER_H
+#define CVD_VIDEOFILEBUFFER_H
+
+#include <vector>
+#include <string>
+#include <fstream>
+#include <errno.h>
+
+#include <cvd/localvideobuffer.h>
+#include <cvd/videobufferflags.h>
+#include <cvd/videofilebuffer_frame.h>
+#include <cvd/image_io.h>
+
+#include <cvd/byte.h>
+#include <cvd/rgb.h>
+
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/avformat.h>
+
+struct AVFormatContext;
+struct AVFrame; 
+
+namespace CVD
+{
+       namespace Exceptions
+       {
+               /// %Exceptions specific to VideoFileBuffer
+               /// @ingroup gException
+               namespace VideoFileBuffer
+               {
+                       /// Base class for all VideoFileBuffer exceptions
+                       /// @ingroup gException
+                       struct All: public CVD::Exceptions::VideoBuffer::All { 
};
+                       /// Unable to open the file as a video stream, for 
various reasons
+                       /// @ingroup gException
+                       struct FileOpen: public All { FileOpen(const 
std::string& file, const std::string& error); ///< Construt from filename and 
error message
+                       };
+                       /// Unable to open allocate a video frame
+                       /// @ingroup gException
+                       struct BadFrameAlloc: public All { BadFrameAlloc(); };
+                       /// Unable to decode the video frame
+                       /// @ingroup gException
+                       struct BadDecode: public All { BadDecode(double t); 
///< Construt from frame timestamp
+                       };
+                       /// get_frame() was called when at the end of the buffer
+                       /// @ingroup gException
+                       struct EndOfFile: public All { EndOfFile(); };
+                       /// seek_to() was called for an invalid timestamp
+                       /// @ingroup gException
+                       struct BadSeek: public All { BadSeek(double t); ///< 
Construt from timestamp
+                       };
+               }
+       }
+
+       /// Internal VideoFileBuffer helpers
+       namespace VFB
+       {
+
+       #ifndef DOXYGEN_IGNORE_INTERNAL
+       template<class C> struct rgb
+       {
+               static const bool 
p=C::Error__type_not_valid___Use_byte_or_rgb_of_byte;
+       };
+
+       template<> struct rgb<CVD::byte>
+       {       
+               static const bool p=false;
+       };
+
+       template<> struct rgb<CVD::Rgb<CVD::byte> >
+       {       
+               static const bool p=true;
+       };
+       #endif 
+
+
+       class A_Frame;
+
+       /// Internal (non type-safe) class used by VideoFileBuffer
+       /// This does the real interfacing with the ffmpeg library
+       class RawVideoFileBuffer 
+       {
+               public:
+                       /// Construct a video buffer to play this file
+                       /// @param file The path to the video file
+                       /// @param is_rgb Is RGB data wanted?
+                       RawVideoFileBuffer(const std::string& file, bool 
is_rgb);
+                       ~RawVideoFileBuffer();
+               
+                       /// The size of the VideoFrames returned by this buffer
+                       ImageRef size()
+                       {
+                               return my_size;
+                       }
+
+                       /// Returns the next frame from the buffer. This 
function blocks until a frame is ready.
+                       void* get_frame();
+                       /// Tell the buffer that you are finished with this 
frame.
+                       /// \param f The frame that you are finished with.
+                       void put_frame(void* f);
+
+                       /// Is there a frame waiting in the buffer? This 
function does not block. 
+                       bool frame_pending()
+                       {
+                               return frame_ready;
+                       }
+
+                       /// Go to a particular point in the video buffer (only 
implemented in buffers of recorded video)
+                       /// \param t The frame time in seconds
+                       void seek_to(double t);
+                       
+                       /// What should the buffer do when it reaches the end 
of the list of files?
+                       /// @param behaviour The desired behaviour
+                       void on_end_of_buffer(VideoBufferFlags::OnEndOfBuffer 
behaviour) 
+                       {
+                               end_of_buffer_behaviour = behaviour;
+                       }
+               
+                       /// What is the (expected) frame rate of this video 
buffer, in frames per second?               
+                       double frames_per_second() 
+                       {
+                           #if LIBAVCODEC_BUILD >= 4754
+                    return pCodecContext->time_base.den / 
static_cast<double>(pCodecContext->time_base.num);
+                #else
+                                   return pCodecContext->frame_rate / 
static_cast<double>(pCodecContext->frame_rate_base);
+                           #endif
+                       };
+                       
+                       /// What is the path to the video file?
+                       std::string file_name() 
+                       {
+                               return pFormatContext->filename;
+                       }
+                       
+                       /// What codec is being used to decode this video?
+                       std::string codec_name() 
+                       {
+                               return pCodecContext->codec_name;
+                       }
+               
+               private:
+                       bool read_next_frame();
+                               
+               private:
+                       ImageRef my_size;
+                       VideoBufferFlags::OnEndOfBuffer end_of_buffer_behaviour;
+                       double start_time;
+                       bool frame_ready;
+
+                       AVFormatContext* pFormatContext;
+                       int video_stream;
+                       AVCodecContext* pCodecContext;
+                   AVFrame* pFrame; 
+               AVFrame* pFrameRGB;
+                       
+                       CVD::Image<CVD::Rgb<byte> > next_frame_rgb;
+                       CVD::Image<CVD::byte> next_frame;
+                       
+                       double frame_time;
+                       bool is_rgb;
+       };
+       }
+
+       ///     A video buffer to play frames from a video file.
+       /// This uses the ffmpeg library (http://ffmpeg.sourceforge.net/) to 
play
+       /// a wide range of video formats, including MPEG (1, 2 and 4) and AVI 
(including
+       /// DivX and DV) files. 
+       /// Provides frames of type CVD::VideoFileFrame and throws exceptions 
of type
+       ///  CVD::Exceptions::VideoFileBuffer
+       /// @param T The pixel type of the video frames. Currently only 
<code>CVD::Rgb<CVD::byte> ></code> and 
+       /// <code>CVD::byte></code> are supported.
+       /// @ingroup gVideoBuffer
+       template<typename T> 
+       class VideoFileBuffer : public CVD::LocalVideoBuffer<T>
+       {
+               private:
+                       VFB::RawVideoFileBuffer vf;
+                       
+       
+               public:
+                       /// Construct a VideoFileBuffer to play this file
+                       /// @param file The path to the video file
+                       VideoFileBuffer(const std::string& file)
+                       :vf(file, VFB::rgb<T>::p)
+                       {
+                       }
+
+                       ~VideoFileBuffer()
+                       {
+                       }
+               
+                       virtual ImageRef size()
+                       {
+                               return vf.size();
+                       }
+
+                       virtual bool frame_pending()
+                       { 
+                               return vf.frame_pending();
+                       }
+
+                       /// What should the buffer do when it reaches the end 
of the list of files?
+                       /// @param behaviour The desired behaviour
+                       virtual void 
on_end_of_buffer(VideoBufferFlags::OnEndOfBuffer behaviour) 
+                       {
+                               vf.on_end_of_buffer(behaviour);
+                       }
+
+                       virtual void seek_to(double t)
+                       {
+                               vf.seek_to(t);
+                       }
+
+                       virtual VideoFileFrame<T> * get_frame()
+                       {
+                               return 
reinterpret_cast<VideoFileFrame<T>*>(vf.get_frame());
+                       }
+
+                       virtual void put_frame(VideoFrame<T>* f)
+                       {
+                               vf.put_frame(f);
+                       }
+                       
+                       // This class additions 
+               
+                       double frame_rate() 
+                       {
+                               return vf.frames_per_second();
+                       }
+
+                       /// What is the path to the video file?
+                       std::string file_name() 
+                       {
+                               return vf.file_name();
+                       }
+
+                       /// What codec is being used to decode this video?
+                       std::string codec_name() 
+                       {
+                               return vf.codec_name();
+                       }
+               
+               private:
+       };
+}
+
+#endif
Index: libcvd/cvd_src/thread.cpp
diff -u /dev/null libcvd/cvd_src/thread.cpp:1.2.2.1
--- /dev/null   Tue May 23 23:41:33 2006
+++ libcvd/cvd_src/thread.cpp   Tue May 23 23:41:33 2006
@@ -0,0 +1,120 @@
+#include <cvd/config.h>
+#include <cvd/thread.h>
+#include <time.h>
+
+#include <iostream>
+
+namespace CVD {
+//Static variables
+bool Thread::ourInitializedFlag = false;
+pthread_key_t Thread::ourKey;
+unsigned int Thread::ourCount;
+
+/** The constructor performs global initialization of the Thread class if 
necessary. */
+Thread::Thread() : myRunningFlag(false), myStopFlag(false)
+{
+   if (!ourInitializedFlag)
+     {
+       init();
+       ourInitializedFlag = true;
+     }
+}
+
+/** Calls stop() and join() if the thread is alive. */
+Thread::~Thread() 
+{
+   if (isRunning()) 
+     {
+       stop();
+       join();
+     }
+}
+
+/** Use PThreads to create a new thread. */
+void Thread::start(Runnable* runnable) 
+{
+    myRunnable = runnable ? runnable : this;
+    myStopFlag = false;
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+    ourCount++;
+    pthread_create(&myID, &attr, threadproc, this);
+}
+
+void Thread::stop() 
+{
+   myStopFlag = true;
+}
+
+bool Thread::shouldStop() const
+{
+   return myStopFlag;
+}
+
+bool Thread::isRunning() const
+{
+   return myRunningFlag;
+}
+
+void Thread::join() 
+{
+   pthread_join(myID,0);
+}
+
+pthread_t Thread::getID() 
+{
+   return myID;
+}
+
+unsigned int Thread::count() 
+{
+   return ourCount;
+}
+
+Thread* Thread::getCurrent() 
+{
+   return (Thread*)pthread_getspecific(ourKey);
+}
+
+/** Uses nanosleep. */
+void Thread::sleep(unsigned int milli) 
+{
+   struct timespec ts = { milli/1000, (milli%1000)*1000000 };
+   nanosleep(&ts, 0);
+}
+
+void Thread::yield()
+{
+#ifdef CVD_HAVE_PTHREAD_YIELD
+  pthread_yield();
+#elif defined(CVD_HAVE_PTHREAD_YIELD_NP)
+  pthread_yield_np();
+#else
+#warning "Thread::yield() not implemented"
+#endif
+}
+
+bool Thread::init() 
+{
+   ourCount = 0;
+   pthread_key_create(&ourKey,0);
+   return true;
+}
+
+void* Thread::threadproc(void* param) 
+{
+   Thread* thread = (Thread*)param;
+   //pthread_setspecific(ourKey, thread);
+   thread->myRunningFlag = true;
+   if (thread->myRunnable)
+     thread->myRunnable->run();
+   else
+     thread->run();
+   thread->myRunningFlag = false;
+   ourCount--;
+
+   return 0;
+}
+
+}
Index: libcvd/cvd_src/videofilebuffer.cc
diff -u /dev/null libcvd/cvd_src/videofilebuffer.cc:1.9.2.1
--- /dev/null   Tue May 23 23:41:33 2006
+++ libcvd/cvd_src/videofilebuffer.cc   Tue May 23 23:41:33 2006
@@ -0,0 +1,435 @@
+/*                       
+       This file is part of the CVD Library.
+
+       Copyright (C) 2005 The Authors
+
+       This library is free software; you can redistribute it and/or
+       modify it under the terms of the GNU Lesser General Public
+       License as published by the Free Software Foundation; either
+       version 2.1 of the License, or (at your option) any later version.
+
+       This library is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+       Lesser General Public License for more details.
+
+       You should have received a copy of the GNU Lesser General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+// Paul Smith 1 March 2005
+// Uses ffmpeg libraries to play most types of video file
+
+#include <string>
+#include <sstream>
+
+#include <cvd/exceptions.h>
+#include <cvd/videofilebuffer.h>
+
+using namespace std;
+
+namespace CVD
+{
+
+using namespace Exceptions::VideoFileBuffer;
+       
+//
+// EXCEPTIONS
+//
+
+Exceptions::VideoFileBuffer::FileOpen::FileOpen(const std::string& name, const 
string& error)
+{
+       what = "RawVideoFileBuffer: Error opening file \"" + name + "\": " + 
error;
+}
+
+Exceptions::VideoFileBuffer::BadFrameAlloc::BadFrameAlloc()
+{
+       what = "RawVideoFileBuffer: Unable to allocate video frame.";
+}
+
+Exceptions::VideoFileBuffer::BadDecode::BadDecode(double t)
+{
+       ostringstream os;
+       os << "RawVideoFileBuffer: Error decoding video frame at time " << t << 
".";
+       what = os.str();
+}
+
+Exceptions::VideoFileBuffer::EndOfFile::EndOfFile()
+{
+       what =  "RawVideoFileBuffer: Tried to read off the end of the file.";
+}
+
+Exceptions::VideoFileBuffer::BadSeek::BadSeek(double t)
+{
+       ostringstream ss;
+       ss << "RawVideoFileBuffer: Seek to time " << t << "s failed.";
+       what = ss.str();
+}
+
+namespace VFB
+{
+//
+// CONSTRUCTOR
+//
+RawVideoFileBuffer::RawVideoFileBuffer(const std::string& file, bool rgbp) :
+       end_of_buffer_behaviour(VideoBufferFlags::RepeatLastFrame),
+       pFormatContext(0),
+       pCodecContext(0),
+       pFrame(0), 
+       pFrameRGB(0),
+       //buffer(0),
+       frame_time(0.0),
+       is_rgb(rgbp)
+{
+       try
+       {
+               // Register the formats and codecs
+               av_register_all();
+       
+               // Now open the video file (and read the header, if present)
+               if(av_open_input_file(&pFormatContext, file.c_str(), NULL, 0, 
NULL) != 0)
+                       throw FileOpen(file, "File could not be opened.");
+               
+               // Read the beginning of the file to get stream information (in 
case there is no header)
+               if(av_find_stream_info(pFormatContext) < 0)
+                       throw FileOpen(file, "Stream information could not be 
read.");
+               
+               // Dump details of the video to standard error
+               dump_format(pFormatContext, 0, file.c_str(), false);
+               
+               // We shall just use the first video stream
+               video_stream = -1;
+               for(int i=0; i < pFormatContext->nb_streams && video_stream == 
-1; i++)
+               {
+                   #if LIBAVFORMAT_BUILD >= 4629
+                       if(pFormatContext->streams[i]->codec->codec_type == 
CODEC_TYPE_VIDEO)
+                               video_stream = i; // Found one!
+                   #else
+                       if(pFormatContext->streams[i]->codec.codec_type == 
CODEC_TYPE_VIDEO)
+                               video_stream = i; // Found one!
+                       #endif
+               }
+               if(video_stream == -1)
+                       throw FileOpen(file, "No video stream found.");
+               
+               // Get the codec context for this video stream
+               #if LIBAVFORMAT_BUILD >= 4629
+               pCodecContext = pFormatContext->streams[video_stream]->codec;
+               #else
+               pCodecContext = &pFormatContext->streams[video_stream]->codec;
+               #endif
+               
+               // Find the decoder for the video stream
+               AVCodec* pCodec = avcodec_find_decoder(pCodecContext->codec_id);
+               if(pCodec == NULL)
+               {
+                       pCodecContext = 0; // Since it's not been opened yet
+                       throw FileOpen(file, "No appropriate codec could be 
found.");
+               }
+               
+               // Open codec
+               if(avcodec_open(pCodecContext, pCodec) < 0)
+               {
+                       pCodecContext = 0; // Since it's not been opened yet
+                       throw FileOpen(file, string(pCodec->name) + " codec 
could not be initialised.");
+               }
+               
+               #if LIBAVCODEC_BUILD < 4754
+               // Hack to fix wrong frame rates
+               if(pCodecContext->frame_rate > 1000 && 
pCodecContext->frame_rate_base == 1)
+                       pCodecContext->frame_rate_base = 1000;
+               #endif
+               
+               
+               // Allocate video frame
+               pFrame = avcodec_alloc_frame();
+               if(pFrame == NULL)
+                       throw BadFrameAlloc();
+               
+               // And a frame to hold the RGB version
+               pFrameRGB = avcodec_alloc_frame();
+               if(pFrameRGB == NULL)
+                       throw BadFrameAlloc();
+               
+               // How big is the buffer?
+               //long num_bytes = avpicture_get_size(PIX_FMT_RGB24, 
pCodecContext->width, pCodecContext->height);
+               my_size = ImageRef(pCodecContext->width, pCodecContext->height);
+
+               // And allocate a contiguous buffer
+               //buffer = new CVD::Rgb<CVD::byte>[my_size.x * my_size.y];
+
+               // Assign this buffer to image planes in pFrameRGB
+               //avpicture_fill((AVPicture *)pFrameRGB, 
reinterpret_cast<uint8_t*>(buffer), PIX_FMT_RGB24, pCodecContext->width, 
pCodecContext->height);
+       
+               // Now read the first frame
+               if(!read_next_frame())
+                       throw EndOfFile();
+               
+               start_time = 0;
+               frame_ready = true;
+       }
+       catch(CVD::Exceptions::All)
+       {
+               // Tidy things up on the heap if we failed part-way through 
constructing
+               if(pFormatContext != 0)
+                   av_close_input_file(pFormatContext);
+               
+               if(pCodecContext != 0)
+                       avcodec_close(pCodecContext);
+               
+               if(pFrame != 0)
+                       av_free(pFrame);
+               
+               if(pFrameRGB != 0)
+                       av_free(pFrameRGB);
+               
+               //if(buffer != 0)
+               //      delete[] buffer;
+               
+               // Now re-throw
+               throw;
+       }
+}
+
+//
+// DESTRUCTOR
+//
+RawVideoFileBuffer::~RawVideoFileBuffer()
+{
+    //delete [] buffer;
+    av_free(pFrameRGB);
+    av_free(pFrame);
+    avcodec_close(pCodecContext);
+    av_close_input_file(pFormatContext);
+}
+
+
+//
+// READ NEXT FRAME
+//
+bool RawVideoFileBuffer::read_next_frame()
+{
+       uint8_t* data;
+
+       //Make next_frame point to a new block of data, getting the sizes 
correct.
+       //Resize always causes seperation of data.
+       if(is_rgb)
+       {
+               next_frame_rgb.resize(my_size);
+               data = reinterpret_cast<uint8_t*>(next_frame_rgb.data());
+       }
+       else
+       {
+               next_frame.resize(my_size);
+               data = reinterpret_cast<uint8_t*>(next_frame.data());
+       }
+
+       //Assign this new memory block 
+       avpicture_fill((AVPicture *)pFrameRGB, data, 
is_rgb?PIX_FMT_RGB24:PIX_FMT_GRAY8, pCodecContext->width, 
pCodecContext->height);
+
+
+    AVPacket packet;
+       packet.stream_index = -1;
+       
+       // How many frames do we read looking for our video stream?
+       // If we assume our streams are interlaced, and some might be interlaced
+       // 2:1, this should probably do
+       const int max_loop = MAX_STREAMS * 2; 
+       
+       int i;
+       for(i = 0; packet.stream_index != video_stream && i < max_loop; i++)
+       {
+               
+       if(av_read_frame(pFormatContext, &packet) < 0)
+                       return false;
+
+               if(packet.stream_index == video_stream)
+               {
+                       // Ask this packet what time it is
+                       if(packet.pts >= 0)
+                               frame_time = packet.pts / 
static_cast<double>(AV_TIME_BASE);
+                       else // sometimes this is reported incorrectly, so guess
+                       {
+                               frame_time = frame_time + 1.0 / 
frames_per_second();
+                       }
+                       
+                       // Decode video frame
+                       int got_picture;
+                       if(avcodec_decode_video(pCodecContext, pFrame, 
&got_picture, 
+                               packet.data, packet.size) == -1)
+                       {
+                               throw BadDecode(frame_time);
+                       }
+       
+                       // Did we get a video frame?
+                       if(got_picture)
+                       {
+                               // Convert the image from its native format to 
RGB
+                               img_convert((AVPicture *)pFrameRGB, 
is_rgb?PIX_FMT_RGB24:PIX_FMT_GRAY8, 
+                                       (AVPicture*)pFrame, 
pCodecContext->pix_fmt, 
+                                       pCodecContext->width, 
pCodecContext->height);
+                               
+                       }
+               }
+
+               // Free the packet that was allocated by av_read_frame
+               av_free_packet(&packet);
+       }
+       
+       // Did we not find one?
+       if(i == max_loop)
+               return false;
+       
+       return true;
+}
+
+
+//
+// GET FRAME
+//
+//VideoFileFrame<byte>* RawVideoFileBuffer::get_frame()
+void* RawVideoFileBuffer::get_frame()
+{
+
+       if(!frame_pending())
+               throw EndOfFile();
+
+//     Don't use - pCC->frame_number doesn't reset after a seek!
+//  Instead, we ask the packet its time when we decode it
+//     double time = start_time + pCodecContext->frame_number * 
pCodecContext->frame_rate_base / static_cast<double>(pCodecContext->frame_rate);
+       //VideoFileFrame<byte>* vf = new VideoFileFrame<byte>(frame_time, 
next_frame);
+
+
+       VideoFileFrame<byte> *vfb = NULL;
+       VideoFileFrame<Rgb<byte> > *vffgb = NULL;
+       
+       if(is_rgb)
+               vfrgb = new VideoFileFrame<byte>(frame_time, next_frame_rgb);
+       else
+               vfb = new VideoFileFrame<byte>(frame_time, next_frame);
+       
+
+       if(!read_next_frame())
+       {
+               switch(end_of_buffer_behaviour)
+               {
+                       case VideoBufferFlags::RepeatLastFrame:
+                               // next_frame is empty because there isn't one, 
so 
+                               // I'll copy the one that I'm about to return 
so that
+                               // I can return it next time as well
+                               if(is_rgb)
+                                       next_frame_rgb.copy_from(*vfrgb);
+                               else
+                                       next_frame.copy_from(*vfb);
+                               break;
+                       
+                       case VideoBufferFlags::UnsetPending:
+                               frame_ready = false;
+                          break;
+                       
+                       case VideoBufferFlags::Loop:
+                               seek_to(start_time);
+                               break;
+               }
+       }
+
+       if(vfb)
+               return vfb;
+       else
+               return vfrgb;
+}
+
+
+template<class C> void delete_frame_or_throw(void* f)
+{
+       VideoFrame<C>* vf = reinterpret_cast<VideoFrame<C>*>(f);
+       VideoFileFrame<C>* vff  = dynamic_cast<VideoFileFrame<C*>(vf);
+       
+       if(!vff)
+               throw Exceptions::VideoBuffer::BadPutFrame();
+       else
+               delete vff;
+}
+
+//
+// PUT FRAME
+//
+void RawVideoFileBuffer::put_frame(void* f)
+{
+       if(is_rgb)
+               delete_frame_or_throw<Rgb<byte> >(f);
+       else
+               delete_frame_or_throw<byte>(f);
+}
+
+//
+// SEEK TO
+//
+void RawVideoFileBuffer::seek_to(double t)
+{      
+       #if LIBAVFORMAT_BUILD >= 4623
+       if(av_seek_frame(pFormatContext, -1, 
static_cast<int64_t>(t*AV_TIME_BASE+0.5), AVSEEK_FLAG_ANY) < 0)
+       #else
+       if(av_seek_frame(pFormatContext, -1, 
static_cast<int64_t>(t*AV_TIME_BASE+0.5)) < 0)
+       #endif
+       {
+               cerr << "av_seek_frame not supported by this codec: performing 
(slow) manual seek" << endl;
+               
+               // Seeking is not properly sorted with some codecs
+               // Fudge it by closing the file and starting again, stepping 
through the frames
+               string file = pFormatContext->filename;
+               av_close_input_file(pFormatContext);
+               avcodec_close(pCodecContext);
+               
+               // Now open the video file (and read the header, if present)
+               if(av_open_input_file(&pFormatContext, file.c_str(), NULL, 0, 
NULL) != 0)
+                       throw FileOpen(file, "File could not be opened.");
+               
+               // Read the beginning of the file to get stream information (in 
case there is no header)
+               if(av_find_stream_info(pFormatContext) < 0)
+                       throw FileOpen(file, "Stream information could not be 
read.");
+               
+               // No need to find the stream--we know which one it is (in 
video_stream)
+               
+               // Get the codec context for this video stream
+               #if LIBAVFORMAT_BUILD >= 4629
+               pCodecContext = pFormatContext->streams[video_stream]->codec;
+               #else
+               pCodecContext = &pFormatContext->streams[video_stream]->codec;
+               #endif
+               
+               // Find the decoder for the video stream
+               AVCodec* pCodec = avcodec_find_decoder(pCodecContext->codec_id);
+               if(pCodec == NULL)
+               {
+                       pCodecContext = 0; // Since it's not been opened yet
+                       throw FileOpen(file, "No appropriate codec could be 
found.");
+               }
+               
+               // Open codec
+               if(avcodec_open(pCodecContext, pCodec) < 0)
+               {
+                       pCodecContext = 0; // Since it's not been opened yet
+                       throw FileOpen(file, string(pCodec->name) + " codec 
could not be initialised.");
+               }
+               
+               start_time = 0;
+               frame_ready = true;
+               
+               // REOPENED FILE OK
+               // Now read frames until we get to the time we want
+               
+               int frames = static_cast<int>((t * frames_per_second() + 0.5));
+               for(int i = 0; i < frames; i++)
+               {
+                       read_next_frame();
+               }
+       }
+       
+       if(!read_next_frame())
+                       throw BadSeek(t);
+}
+
+}
+} // namespace CVD




reply via email to

[Prev in Thread] Current Thread [Next in Thread]