00001 /*!@file Media/MgzJEncoder.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/MgzJEncoder.H" 00036 00037 #include "Image/Image.H" 00038 #include "Image/Pixels.H" 00039 #include "Util/log.H" 00040 #include "Util/sformat.H" 00041 #include "rutz/trace.h" 00042 00043 #include <zlib.h> 00044 #include <sstream> 00045 00046 // ###################################################################### 00047 MgzJEncoder::MgzJEncoder(const std::string& fname, const int complev) 00048 { 00049 LINFO("Opening File: %s", fname.c_str()); 00050 itsFile.open(fname.c_str(), std::ios::out | std::ios::binary); 00051 itsComplev = complev; 00052 } 00053 00054 // ###################################################################### 00055 MgzJEncoder::~MgzJEncoder() 00056 { 00057 this->close(); 00058 } 00059 00060 // ###################################################################### 00061 int MgzJEncoder::close() 00062 { 00063 if(itsFile.is_open()) 00064 { 00065 LINFO("Please wait... Writing %lu entries to the file journal", (unsigned long)itsJournal.size()); 00066 //Get the current position of the put pointer - this will be the start location of the journal 00067 uint64 journal_position = itsFile.tellp(); 00068 00069 //Allocate the memory for our journal. 00070 // 0: Number of entries (8 bytes) 00071 // 8: Flags (8 bytes) 00072 // 16: JOURNAL (? bytes) 00073 // ??: Journal Start (8 bytes) 00074 size_t journal_size = 8 + 8 + itsJournal.size() * sizeof(MgzJEncoder::journalEntry) + 8; 00075 byte journal[journal_size]; 00076 00077 //Copy the number of journal entries to the journal buffer 00078 uint64 num_entries = itsJournal.size(); 00079 memcpy(journal, (char*)&num_entries, 8); 00080 00081 //Copy the format flags to the journal buffer. 00082 //This is just reserved space, in case we need to later add some more meta information, 00083 //such as some versioning of the journal entries, or journal compression, etc... 00084 uint64 flags = 0; 00085 memcpy(journal+8, (char*)&flags, 8); 00086 00087 //Serialize all of our journal entries and write them to disk 00088 //TODO: Investigate just using a big memcpy or std::copy here, as general 00089 //consensus says that vectors are always contiguous 00090 for(size_t jIdx=0; jIdx<itsJournal.size(); jIdx++) 00091 { 00092 00093 //Calculate the position of this new journal entry 00094 size_t jPos = 16+jIdx*sizeof(MgzJEncoder::journalEntry); 00095 00096 //Copy this entry into the journal buffer 00097 memcpy(journal+jPos, (char *)&itsJournal[jIdx], sizeof(MgzJEncoder::journalEntry)); 00098 } 00099 00100 //The last 64 bits of the file will be the file position of the start of the journal 00101 memcpy(journal + 8 + 8 + itsJournal.size() * sizeof(MgzJEncoder::journalEntry), &journal_position, 8); 00102 00103 //Write the journal to disk 00104 itsFile.write((char*)journal, journal_size); 00105 00106 itsFile.close(); 00107 } 00108 return 1; 00109 } 00110 00111 // ###################################################################### 00112 void MgzJEncoder::writeFrame(const GenericFrame& frame) 00113 { 00114 //Create a journal entry for this new frame 00115 MgzJEncoder::journalEntry entry; 00116 entry.pix_type = frame.nativeType(); 00117 entry.width = frame.getWidth(); 00118 entry.height = frame.getHeight(); 00119 00120 //Fill in the special fields if necessary 00121 if(frame.nativeType() == GenericFrame::VIDEO) 00122 { 00123 entry.flags = frame.asVideo().getMode(); 00124 entry.byte_swap = frame.asVideo().getByteSwap(); 00125 } 00126 else 00127 { 00128 entry.flags = frame.floatFlags(); 00129 } 00130 00131 int num_pix = frame.getWidth() * frame.getHeight(); 00132 size_t num_bytes = -1; 00133 unsigned char* frameBase = NULL; 00134 switch(frame.nativeType()) 00135 { 00136 case GenericFrame::GRAY_U8: 00137 num_bytes = sizeof(byte) * num_pix; 00138 frameBase = (unsigned char*)frame.asGrayU8().getArrayPtr(); 00139 break; 00140 case GenericFrame::GRAY_U16: 00141 num_bytes = sizeof(uint16) * num_pix; 00142 frameBase = (unsigned char*)frame.asGrayU16().getArrayPtr(); 00143 break; 00144 case GenericFrame::GRAY_F32: 00145 num_bytes = sizeof(float) * num_pix; 00146 frameBase = (unsigned char*)frame.asGrayF32().getArrayPtr(); 00147 break; 00148 case GenericFrame::RGB_U8: 00149 num_bytes = sizeof(PixRGB<byte>) * num_pix; 00150 frameBase = (unsigned char*)frame.asRgbU8().getArrayPtr(); 00151 break; 00152 case GenericFrame::RGB_U16: 00153 num_bytes = sizeof(PixRGB<uint16>) * num_pix; 00154 frameBase = (unsigned char*)frame.asRgbU16().getArrayPtr(); 00155 break; 00156 case GenericFrame::RGB_F32: 00157 num_bytes = sizeof(PixRGB<float>) * num_pix; 00158 frameBase = (unsigned char*)frame.asRgbF32().getArrayPtr(); 00159 break; 00160 case GenericFrame::VIDEO: 00161 num_bytes = frame.asVideo().getBufSize(); 00162 frameBase = (unsigned char*)frame.asVideo().getBuffer(); 00163 break; 00164 case GenericFrame::NONE: 00165 //nothing to do here 00166 break; 00167 default: 00168 LFATAL("Cannot write frames of type %s", frame.nativeTypeName().c_str()); 00169 } 00170 00171 //Allocate an output buffer, allowing for some extra space for a header in case 00172 //our input data is totally incompressable 00173 size_t outputBufferSize = num_bytes + 1000; 00174 unsigned char outputBuffer[outputBufferSize]; 00175 00176 //Setup our DEFLATE compression stream 00177 z_stream strm; 00178 strm.zalloc = Z_NULL; 00179 strm.zfree = Z_NULL; 00180 strm.opaque = Z_NULL; 00181 00182 int msg = deflateInit(&strm, itsComplev); 00183 if(msg != Z_OK) 00184 { 00185 std::stringstream reason; 00186 reason << "Could not initialize mgzj encoder ("; 00187 switch(msg) 00188 { 00189 case Z_MEM_ERROR: 00190 reason << "Z_MEM_ERROR: Insufficient Memory"; 00191 break; 00192 case Z_STREAM_ERROR: 00193 reason << "Z_STREAM_ERROR: Likely an invalid compression level (You chose" << itsComplev << ")"; 00194 break; 00195 case Z_VERSION_ERROR: 00196 reason << "Z_VERSION_ERROR: You're using an incompatible version of zlib.h"; 00197 break; 00198 default: 00199 reason << "Unknown Error!"; 00200 break; 00201 } 00202 reason << ")"; 00203 LFATAL("%s", reason.str().c_str()); 00204 } 00205 00206 //Setup the input and output buffers 00207 strm.avail_in = num_bytes; 00208 strm.next_in = frameBase; 00209 strm.avail_out = outputBufferSize; 00210 strm.next_out = outputBuffer; 00211 00212 //Perform the actual decompression and just die on any errors 00213 msg = deflate(&strm, Z_FINISH); 00214 (void)deflateEnd(&strm); 00215 if(msg != Z_STREAM_END) 00216 { 00217 std::stringstream reason; 00218 reason << "Failure to deflate ("; 00219 switch(msg) 00220 { 00221 case Z_OK: 00222 reason << "Z_OK"; 00223 break; 00224 case Z_STREAM_ERROR: 00225 reason << "Z_STREAM_ERROR"; 00226 break; 00227 case Z_BUF_ERROR: 00228 reason << "Z_BUF_ERROR"; 00229 break; 00230 default: 00231 reason << "Unknown Error!"; 00232 break; 00233 } 00234 reason << ")"; 00235 LFATAL("%s", reason.str().c_str()); 00236 } 00237 size_t compressedSize = outputBufferSize - strm.avail_out; 00238 00239 //Fill in the rest of the journal entry for this frame, and push it onto the 00240 //journal 00241 entry.start_byte = itsFile.tellp(); 00242 entry.end_byte = entry.start_byte + compressedSize; 00243 itsJournal.push_back(entry); 00244 00245 //Write the compressed frame to disk 00246 itsFile.write((const char*)outputBuffer, compressedSize); 00247 } 00248 00249 00250