00001 /*!@file Media/SequenceFileStream.C Read frames from .seq video files */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rand Voorhies <voorhies at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Media/SequenceFileStream.C $ 00035 // $Id: SequenceFileStream.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #include "Media/SequenceFileStream.H" 00039 #include "Component/ModelOptionDef.H" 00040 #include "Raster/DeBayer.H" 00041 #include "Image/Image.H" 00042 #include "Image/Pixels.H" 00043 #include "Raster/GenericFrame.H" 00044 #include "Transport/TransportOpts.H" // for MOC_INPUT 00045 #include "Util/log.H" 00046 #include "rutz/trace.h" 00047 00048 #include <stdio.h> 00049 #include <fcntl.h> 00050 00051 const ModelOptionDef OPT_SequenceFileStreamUseMmap = 00052 { MODOPT_ARG(bool), "SequenceFileStreamUseMmap", &MOC_INPUT, OPTEXP_CORE, 00053 "Whether to use mmap() instead of read() to stream data from disk. The" 00054 "default is to use mmap(), which may be significantly faster, but may" 00055 "be somewhat less portable.", 00056 "seqfile-use-mmap", '\0', "<true|false>", "false" }; 00057 00058 // ###################################################################### 00059 SequenceFileStream::SequenceFileStream(OptionManager& mgr, 00060 const std::string& descrName, const std::string& tagName) : 00061 FrameIstream(mgr, descrName, tagName), 00062 itsUseMmap(&OPT_SequenceFileStreamUseMmap, this), 00063 itsFrame(), itsFrameSpec(), itsFrameSpecValid(false), itsFileHandle(-1), 00064 itsMmapFile() 00065 { } 00066 00067 // ###################################################################### 00068 SequenceFileStream::~SequenceFileStream() 00069 { } 00070 00071 // ###################################################################### 00072 void SequenceFileStream::setConfigInfo(const std::string& filename) 00073 { 00074 this->setFileName(filename); 00075 } 00076 00077 00078 // ###################################################################### 00079 GenericFrameSpec SequenceFileStream::peekFrameSpec() 00080 { 00081 GVX_TRACE(__PRETTY_FUNCTION__); 00082 00083 if (!itsFrameSpecValid) 00084 { 00085 if (itsFrame.initialized() == false) itsFrame = readFrame(); 00086 00087 itsFrameSpec = itsFrame.frameSpec(); 00088 itsFrameSpecValid = true; 00089 } 00090 00091 return itsFrameSpec; 00092 } 00093 00094 // ###################################################################### 00095 void SequenceFileStream::setFileName(const std::string& fname) 00096 { 00097 GVX_TRACE(__PRETTY_FUNCTION__); 00098 00099 // Open the file 00100 if (itsFileHandle != -1) close(itsFileHandle); 00101 00102 #ifdef HAVE_O_LARGEFILE 00103 itsFileHandle = open(fname.c_str(), O_LARGEFILE | O_RDONLY); 00104 #else 00105 itsFileHandle = open(fname.c_str(), O_RDONLY); 00106 #endif 00107 00108 if(itsFileHandle == -1) PLFATAL("Could Not Open File %s", fname.c_str()); 00109 00110 int32_t header[146]; 00111 ssize_t headerSize; 00112 00113 // Read and parse the file header 00114 headerSize = read(itsFileHandle, &header, (size_t)(sizeof(int32_t) * 146) ); 00115 00116 // Make sure then entire header was read 00117 if (headerSize != size_t(sizeof(int32_t) * 146) ) 00118 LFATAL("Could not fully read .seq file header. File: %s", fname.c_str()); 00119 00120 // Check the version number on the header 00121 if(header[7] != 3) 00122 LFATAL("Wrong version number found in .seq file header (%d != 3).", header[7]); 00123 00124 // Check the magic number on the header 00125 if(header[0] != 0xfeed) 00126 LFATAL("Missing magic number from .seq file header (%x != 0xfeed).", header[0]); 00127 00128 if(header[139] != 8 || header[140] != 8 || (header[142] != 100 && header[142] != 101)) 00129 LFATAL("seq file in a format other than 8-bit bayer\n"); 00130 00131 itsDataOffset = header[8]; // need for seek 00132 itsWidth = header[137]; // stored image dimensions, for read 00133 itsHeight = header[138]; 00134 itsFrameCount = header[143]; // number of frames 00135 itsFirstFrame = header[144]; // start number, always 0? 00136 itsTrueImageSize = header[145]; // need for seek 00137 itsImageSizeBytes = header[141]; // amount to read 00138 00139 LINFO("Opening Sequence File with %d Frames", itsFrameCount); 00140 00141 // do we want to use mmap'd I/O? 00142 if (itsUseMmap.getVal()) { 00143 // close the file and instead get a mapped_file going: 00144 close(itsFileHandle); itsFileHandle = -1; 00145 itsMmapFile.reset(new rutz::mapped_infile(fname.c_str())); 00146 } 00147 } 00148 00149 bool SequenceFileStream::setFrameNumber(int n) 00150 { 00151 if ((unsigned int)n > itsFrameCount) return false; 00152 00153 itsFrameOffset = n; 00154 return true; 00155 } 00156 00157 // ###################################################################### 00158 GenericFrame SequenceFileStream::readFrame() 00159 { 00160 GVX_TRACE(__PRETTY_FUNCTION__); 00161 00162 if (itsUseMmap.getVal()) { if (itsMmapFile.is_invalid()) LFATAL("File not mmap'd"); } 00163 else { if (itsFileHandle == -1) LFATAL("File not open"); } 00164 00165 GenericFrame ret; 00166 00167 // do we already have a frame because we peeked its specs? 00168 if (itsFrame.initialized()) { 00169 ret = itsFrame; 00170 itsFrame = GenericFrame(); 00171 } else { 00172 // Calculate the desired seek position 00173 off_t seekPosition = itsDataOffset + (itsFirstFrame + itsFrameOffset) * itsTrueImageSize; 00174 00175 if (itsUseMmap.getVal()) { 00176 // use mmap I/O. In fact, we don't read anything proper until we 00177 // call deBayer() which will automatically swap in data as it 00178 // processes the pixels. Yeah the attach() below is hacky with 00179 // the casting, we need to remember that the mmap'd memory is 00180 // read-only so we should not try to modify any pixel in that 00181 // temporary image: 00182 00183 //FIXME: this has issues: 00184 // Image<byte> img; 00185 // img.attach(const_cast<byte*>(reinterpret_cast<const byte *>(itsMmapFile->memory())) + 00186 // seekPosition, itsWidth, itsHeight); 00187 00188 //FIXME: I believe this makes a deep copy... 00189 Image<byte> img(reinterpret_cast<const byte *>(itsMmapFile->memory()) + seekPosition, itsWidth, itsHeight); 00190 00191 // Debayer the image to make it RGB; this will swap in the 00192 // necessary pages as the memory is being accessed by the 00193 // dBayer function: 00194 Image<PixRGB<byte> > frame = deBayer(img, BAYER_GRBG); 00195 ret = GenericFrame(frame); 00196 00197 //img.detach(); 00198 } else { 00199 // use regular I/O; Seek to the desired frame 00200 #ifdef HAVE_O_LARGEFILE 00201 lseek64(itsFileHandle, seekPosition, SEEK_SET); 00202 #else 00203 lseek(itsFileHandle, seekPosition, SEEK_SET); 00204 #endif 00205 00206 // Read the frame as raw bytes 00207 Image<byte> tempImage(itsWidth, itsHeight, NO_INIT); 00208 00209 size_t numRead = read(itsFileHandle, tempImage.getArrayPtr(), itsWidth * itsHeight); 00210 00211 if (numRead <= 0) { LERROR("Frame Not Read From Sequence File"); return GenericFrame(); } 00212 00213 // Debayer the image to make it RGB 00214 Image<PixRGB<byte> > frame = deBayer(tempImage, BAYER_GRBG); 00215 ret = GenericFrame(frame); 00216 } 00217 // ready for next frame: 00218 ++itsFrameOffset; 00219 } 00220 00221 return ret; 00222 } 00223 00224