00001 /*!@file Media/MgzJDecoder.C Low-level class to decode mgzj 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: Randolph Voorhies <voories at usc dot edu> 00034 00035 #include "Media/MgzJDecoder.H" 00036 #include <sys/errno.h> 00037 00038 // ###################################################################### 00039 MgzJDecoder::MgzJDecoder(const std::string& fname) 00040 : 00041 itsFileName(fname) 00042 { 00043 init(); 00044 } 00045 00046 // ###################################################################### 00047 MgzJDecoder::~MgzJDecoder() 00048 { 00049 shutdown(); 00050 } 00051 00052 00053 // ###################################################################### 00054 void MgzJDecoder::init() 00055 { 00056 LDEBUG("Opening File: %s", itsFileName.c_str()); 00057 00058 //Open the file in binary input mode, and position the get pointer 00059 //at the end of the file 00060 itsFile.open(itsFileName.c_str(), std::ios::in|std::ios::binary|std::ios::ate); 00061 00062 if(!itsFile.is_open()) 00063 LFATAL("Could not open file: %s", itsFileName.c_str()); 00064 00065 //Get the size of the file 00066 std::ifstream::pos_type fsize = itsFile.tellg(); 00067 00068 //Find the position of the journal start 00069 uint64 journal_start; 00070 itsFile.seekg(-8, std::ios::end); 00071 itsFile.read((char*)&journal_start, 8); 00072 00073 //Read in the 16 bytes of meta-meta information 00074 byte meta_meta_buffer[16]; 00075 itsFile.seekg(journal_start, std::ios::beg); 00076 itsFile.read((char*)meta_meta_buffer, 16); 00077 00078 //Get the number of journal entries 00079 uint64 num_entries; 00080 memcpy((char*)&num_entries, meta_meta_buffer, 8); 00081 00082 //Get the flags (for now just assert that they are 0. Anything else 00083 //should be an error) 00084 uint64 flags; 00085 memcpy((char*)&flags, meta_meta_buffer+8, 8); 00086 ASSERT(flags == 0); 00087 00088 //Calculate the file offset where the actual journal entries begin 00089 uint64 journal_data_start = journal_start + 16; 00090 00091 //Allocate a buffer to store the whole journal, and read it in 00092 uint64 journal_buf_size = (uint64)fsize - journal_data_start - 8; 00093 byte journal[journal_buf_size]; 00094 itsFile.seekg(journal_data_start, std::ios::beg); 00095 itsFile.read((char*)journal, journal_buf_size); 00096 00097 //Calculate the size of each entry 00098 uint64 entry_size = journal_buf_size / num_entries; 00099 00100 //Loop through the buffer to deserialize the journal entries 00101 itsJournal.clear(); 00102 for(uint64 buf_pos=0; buf_pos < journal_buf_size; buf_pos += entry_size) 00103 { 00104 MgzJEncoder::journalEntry entry; 00105 memcpy((char*)&entry, journal+buf_pos, sizeof(MgzJEncoder::journalEntry)); 00106 itsJournal.push_back(entry); 00107 } 00108 00109 } 00110 00111 void MgzJDecoder::shutdown() 00112 { 00113 if(itsFile.is_open()) 00114 itsFile.close(); 00115 } 00116 00117 // ###################################################################### 00118 GenericFrame MgzJDecoder::readFrame() 00119 { 00120 00121 //Grab the journal entry for this frame and allocate an appropriate 00122 //GenericFrame 00123 MgzJEncoder::journalEntry entry = itsJournal.at(itsFrameNum); 00124 const Dims dims(entry.width, entry.height); 00125 const GenericFrame::NativeType pix_type = GenericFrame::NativeType(entry.pix_type); 00126 const int num_pix = dims.sz(); 00127 GenericFrame frame; 00128 00129 //Read in the compressed image to a buffer 00130 uint64 comp_image_buf_size = entry.end_byte - entry.start_byte; 00131 byte comp_image_buf[comp_image_buf_size]; 00132 itsFile.seekg(entry.start_byte, std::ios::beg); 00133 itsFile.read((char*)comp_image_buf, comp_image_buf_size); 00134 00135 //Prepare zlib to do the decompression 00136 z_stream strm; 00137 strm.zalloc = Z_NULL; 00138 strm.zfree = Z_NULL; 00139 strm.opaque = Z_NULL; 00140 strm.avail_in = 0; 00141 strm.next_in = Z_NULL; 00142 int ret = inflateInit(&strm); 00143 if(ret != Z_OK) 00144 LFATAL("Could not initialize zlib!"); 00145 00146 strm.avail_in = comp_image_buf_size; 00147 strm.next_in = comp_image_buf; 00148 switch(pix_type) 00149 { 00150 case GenericFrame::GRAY_U8: 00151 { 00152 Image<byte> img(dims, NO_INIT); 00153 strm.avail_out = num_pix * sizeof(byte); 00154 strm.next_out = (unsigned char*)img.getArrayPtr(); 00155 ret = inflate(&strm, Z_FINISH); 00156 if(ret != Z_STREAM_END) 00157 { LFATAL("Could Not Inflate Frame! %d, %s", ret, strm.msg); } 00158 frame = GenericFrame(img); 00159 00160 break; 00161 } 00162 case GenericFrame::GRAY_U16: 00163 { 00164 Image<uint16> img(dims, NO_INIT); 00165 strm.avail_out = num_pix * sizeof(uint16); 00166 strm.next_out = (unsigned char*)img.getArrayPtr(); 00167 ret = inflate(&strm, Z_FINISH); 00168 if(ret != Z_STREAM_END) 00169 { LFATAL("Could Not Inflate Frame! %d, %s", ret, strm.msg); } 00170 frame = GenericFrame(img); 00171 00172 break; 00173 } 00174 case GenericFrame::GRAY_F32: 00175 { 00176 Image<float> img(dims, NO_INIT); 00177 strm.avail_out = num_pix * sizeof(float); 00178 strm.next_out = (unsigned char*)img.getArrayPtr(); 00179 ret = inflate(&strm, Z_FINISH); 00180 if(ret != Z_STREAM_END) 00181 { LFATAL("Could Not Inflate Frame! %d, %s", ret, strm.msg); } 00182 frame = GenericFrame(img, entry.flags); 00183 00184 break; 00185 } 00186 case GenericFrame::RGB_U8: 00187 { 00188 Image<PixRGB<byte> > img(dims, NO_INIT); 00189 strm.avail_out = num_pix * sizeof(PixRGB<byte>); 00190 strm.next_out = (unsigned char*)img.getArrayPtr(); 00191 ret = inflate(&strm, Z_FINISH); 00192 if(ret != Z_STREAM_END) 00193 { LFATAL("Could Not Inflate Frame! %d, %s", ret, strm.msg); } 00194 frame = GenericFrame(img); 00195 00196 break; 00197 } 00198 case GenericFrame::RGB_U16: 00199 { 00200 Image<PixRGB<uint16> > img(dims, NO_INIT); 00201 strm.avail_out = num_pix * sizeof(PixRGB<uint16>); 00202 strm.next_out = (unsigned char*)img.getArrayPtr(); 00203 ret = inflate(&strm, Z_FINISH); 00204 if(ret != Z_STREAM_END) 00205 { LFATAL("Could Not Inflate Frame! %d, %s", ret, strm.msg); } 00206 frame = GenericFrame(img); 00207 00208 break; 00209 } 00210 case GenericFrame::RGB_F32: 00211 { 00212 Image<PixRGB<float> > img(dims, NO_INIT); 00213 strm.avail_out = num_pix * sizeof(PixRGB<float>); 00214 strm.next_out = (unsigned char*)img.getArrayPtr(); 00215 ret = inflate(&strm, Z_FINISH); 00216 if(ret != Z_STREAM_END) 00217 { LFATAL("Could Not Inflate Frame! %d, %s", ret, strm.msg); } 00218 frame = GenericFrame(img, entry.flags); 00219 00220 break; 00221 } 00222 case GenericFrame::VIDEO: 00223 { 00224 const size_t vidSize = getFrameSize(VideoFormat(entry.flags), dims); 00225 ArrayHandle<byte> vidBuffer(new ArrayData<byte>(Dims(vidSize,1), NO_INIT)); 00226 strm.avail_out = vidSize; 00227 strm.next_out = (unsigned char*)vidBuffer.uniq().dataw(); 00228 ret = inflate(&strm, Z_FINISH); 00229 if(ret != Z_STREAM_END) 00230 { LFATAL("Could Not Inflate Frame! %d, %s", ret, strm.msg); } 00231 frame = GenericFrame(VideoFrame(vidBuffer, dims, VideoFormat(entry.flags), bool(entry.byte_swap))); 00232 break; 00233 } 00234 default: 00235 LFATAL("Could Not Open Frame Of Type: %d!", pix_type); 00236 } 00237 00238 inflateEnd(&strm); 00239 return frame; 00240 } 00241 00242 // ###################################################################### 00243 int MgzJDecoder::getNumFrames() 00244 { 00245 return itsJournal.size(); 00246 } 00247 00248 // ###################################################################### 00249 bool MgzJDecoder::setFrameNumber(unsigned int n) 00250 { 00251 if(n < itsJournal.size()) 00252 { 00253 itsFrameNum = n; 00254 return true; 00255 } 00256 LINFO("Could not set frame number to %d (only %lu frames available)", n, (unsigned long)itsJournal.size()); 00257 return false; 00258 } 00259 00260 00261