00001 /*!@file Media/UcbMpegEncoder.C Thin c++ wrapper around mpeg_encode/ppmtompeg */ 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: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Media/UcbMpegEncoder.C $ 00035 // $Id: UcbMpegEncoder.C 8903 2007-10-25 22:56:57Z rjpeters $ 00036 // 00037 00038 #ifndef MEDIA_UCBMPEGENCODER_C_DEFINED 00039 #define MEDIA_UCBMPEGENCODER_C_DEFINED 00040 00041 #include "Media/UcbMpegEncoder.H" 00042 00043 #include "Image/Image.H" 00044 #include "Image/Pixels.H" 00045 #include "Raster/GenericFrame.H" 00046 #include "Raster/PnmWriter.H" 00047 #include "Util/log.H" 00048 #include "Util/sformat.H" 00049 #include "Video/VideoFrame.H" 00050 #include "rutz/pipe.h" 00051 #include "rutz/trace.h" 00052 00053 #include <fstream> 00054 00055 UcbMpegParams UcbMpegParams::basic() 00056 { 00057 GVX_TRACE(__PRETTY_FUNCTION__); 00058 UcbMpegParams parms; 00059 00060 parms.PATTERN = "IBBPBBPBBPBBPBB"; 00061 parms.GOP_SIZE = 30; 00062 parms.SLICES_PER_FRAME = 1; 00063 parms.PIXEL = "HALF"; 00064 parms.RANGE = 10; 00065 parms.PSEARCH_ALG = "LOGARITHMIC"; 00066 parms.BSEARCH_ALG = "CROSS2"; 00067 parms.IQSCALE = 8; 00068 parms.PQSCALE = 10; 00069 parms.BQSCALE = 25; 00070 parms.REFERENCE_FRAME = "ORIGINAL"; 00071 00072 return parms; 00073 } 00074 00075 UcbMpegParams UcbMpegParams::hq() 00076 { 00077 GVX_TRACE(__PRETTY_FUNCTION__); 00078 UcbMpegParams parms; 00079 00080 parms.PATTERN = "IBBPBBPBBPBBPBB"; 00081 parms.GOP_SIZE = 30; 00082 parms.SLICES_PER_FRAME = 1; 00083 parms.PIXEL = "HALF"; 00084 parms.RANGE = 10; 00085 parms.PSEARCH_ALG = "LOGARITHMIC"; 00086 parms.BSEARCH_ALG = "CROSS2"; 00087 parms.IQSCALE = 1; 00088 parms.PQSCALE = 1; 00089 parms.BQSCALE = 1; 00090 parms.REFERENCE_FRAME = "DECODED"; 00091 00092 return parms; 00093 } 00094 00095 UcbMpegParams UcbMpegParams::superhq() 00096 { 00097 GVX_TRACE(__PRETTY_FUNCTION__); 00098 UcbMpegParams parms; 00099 00100 parms.PATTERN = "I"; 00101 parms.GOP_SIZE = 1; 00102 parms.SLICES_PER_FRAME = 1; 00103 parms.PIXEL = "HALF"; 00104 parms.RANGE = 10; 00105 parms.PSEARCH_ALG = "LOGARITHMIC"; 00106 parms.BSEARCH_ALG = "CROSS2"; 00107 parms.IQSCALE = 1; 00108 parms.PQSCALE = 1; 00109 parms.BQSCALE = 1; 00110 parms.REFERENCE_FRAME = "DECODED"; 00111 00112 return parms; 00113 } 00114 00115 UcbMpegEncoder::UcbMpegEncoder(const std::string& exename, 00116 const std::string& outname, 00117 const UcbMpegParams& params, 00118 const double framerate) : 00119 itsExeName(exename), 00120 itsOutFname(outname), 00121 itsParams(params), 00122 itsParamFname(), 00123 itsFrameRate(framerate), 00124 itsVideoFormat(VIDFMT_AUTO), 00125 itsSubprocess(0), 00126 itsDims() 00127 { 00128 GVX_TRACE(__PRETTY_FUNCTION__); 00129 } 00130 00131 UcbMpegEncoder::~UcbMpegEncoder() 00132 { 00133 GVX_TRACE(__PRETTY_FUNCTION__); 00134 this->close(); 00135 00136 delete itsSubprocess; 00137 } 00138 00139 int UcbMpegEncoder::close() 00140 { 00141 GVX_TRACE(__PRETTY_FUNCTION__); 00142 int result = 0; 00143 00144 if (itsSubprocess != 0) 00145 { 00146 itsSubprocess->close_out(); 00147 00148 result = itsSubprocess->exit_status(); 00149 00150 LINFO("%s exited with status %d", itsExeName.c_str(), result); 00151 00152 delete itsSubprocess; 00153 itsSubprocess = 0; 00154 } 00155 00156 if (itsParamFname.length() > 0) 00157 { 00158 remove(itsParamFname.c_str()); 00159 itsParamFname = std::string(); 00160 } 00161 00162 return result; 00163 } 00164 00165 void UcbMpegEncoder::makeParmsFile(const VideoFrame& f) 00166 { 00167 GVX_TRACE(__PRETTY_FUNCTION__); 00168 static int counter = 0; 00169 00170 if (f.getDims().w() % 16 != 0) 00171 LFATAL("%s requires the image width to be a multiple of 16, " 00172 "but the actual image width was %d", 00173 itsExeName.c_str(), f.getDims().w()); 00174 00175 if (f.getDims().h() % 16 != 0) 00176 LFATAL("%s requires the image height to be a multiple of 16, " 00177 "but the actual image height was %d", 00178 itsExeName.c_str(), f.getDims().h()); 00179 00180 itsDims = f.getDims(); 00181 00182 itsParamFname = sformat("/tmp/mpegencode-params-%d-%d.txt", 00183 int(getpid()), counter++); 00184 00185 FILE* pf = fopen(itsParamFname.c_str(), "w"); 00186 00187 if (pf == 0) 00188 LFATAL("couldn't open %s for writing", itsParamFname.c_str()); 00189 00190 fprintf(pf, "PATTERN %s\n", itsParams.PATTERN); 00191 fprintf(pf, "GOP_SIZE %d\n", itsParams.GOP_SIZE); 00192 fprintf(pf, "SLICES_PER_FRAME %d\n", itsParams.SLICES_PER_FRAME); 00193 fprintf(pf, "PIXEL %s\n", itsParams.PIXEL); 00194 fprintf(pf, "RANGE %d\n", itsParams.RANGE); 00195 fprintf(pf, "PSEARCH_ALG %s\n", itsParams.PSEARCH_ALG); 00196 fprintf(pf, "BSEARCH_ALG %s\n", itsParams.BSEARCH_ALG); 00197 fprintf(pf, "IQSCALE %d\n", itsParams.IQSCALE); 00198 fprintf(pf, "PQSCALE %d\n", itsParams.PQSCALE); 00199 fprintf(pf, "BQSCALE %d\n", itsParams.BQSCALE); 00200 fprintf(pf, "REFERENCE_FRAME %s\n", itsParams.REFERENCE_FRAME); 00201 00202 fprintf(pf, "FORCE_ENCODE_LAST_FRAME 1\n"); 00203 fprintf(pf, "FRAME_RATE %.2f\n", itsFrameRate); 00204 fprintf(pf, "OUTPUT %s\n", itsOutFname.c_str()); 00205 fprintf(pf, "SIZE %dx%d\n", f.getDims().w(), f.getDims().h()); 00206 00207 switch (f.getMode()) 00208 { 00209 case VIDFMT_UYVY: 00210 case VIDFMT_YUV422: 00211 fprintf(pf, "BASE_FILE_FORMAT YUV\n"); 00212 fprintf(pf, "YUV_FORMAT ABEKAS\n"); 00213 itsVideoFormat = f.getMode(); 00214 LINFO("writing frames in YUV/ABEKAS format"); 00215 break; 00216 00217 // NOTE: "YUV_FORMAT PHILLIPS" would be YVYU, but we don't have 00218 // a VIDFMT code for that layout 00219 00220 case VIDFMT_YUV420P: 00221 fprintf(pf, "BASE_FILE_FORMAT YUV\n"); 00222 fprintf(pf, "YUV_FORMAT UCB\n"); 00223 itsVideoFormat = f.getMode(); 00224 LINFO("writing frames in YUV/UCB format"); 00225 break; 00226 00227 default: 00228 fprintf(pf, "BASE_FILE_FORMAT PPM\n"); 00229 itsVideoFormat = VIDFMT_AUTO; // just convert through toRgb() 00230 LINFO("writing frames in PPM format"); 00231 break; 00232 } 00233 00234 fprintf(pf, "INPUT_DIR stdin\n"); 00235 fprintf(pf, "INPUT_CONVERT *\n"); 00236 fprintf(pf, "INPUT\n"); 00237 fprintf(pf, "END_INPUT\n"); 00238 00239 fclose(pf); 00240 00241 // now echo the params file back to the user for debugging: 00242 { 00243 std::ifstream ifs(itsParamFname.c_str()); 00244 int lineno = 0; 00245 std::string line; 00246 while (std::getline(ifs, line)) 00247 { 00248 LDEBUG("params:%02d: %s", ++lineno, line.c_str()); 00249 } 00250 } 00251 } 00252 00253 void UcbMpegEncoder::writeVideoFrame(const VideoFrame& f) 00254 { 00255 GVX_TRACE(__PRETTY_FUNCTION__); 00256 00257 if (itsSubprocess == 0) 00258 { 00259 this->makeParmsFile(f); 00260 itsSubprocess = new rutz::bidir_pipe; 00261 00262 itsSubprocess->block_child_sigint(); 00263 00264 itsSubprocess->init(itsExeName.c_str(), 00265 "-realquiet", 00266 itsParamFname.c_str(), 00267 0); 00268 00269 LDEBUG("initialized subprocess '%s -realquiet %s'", 00270 itsExeName.c_str(), itsParamFname.c_str()); 00271 } 00272 00273 if (f.getDims() != itsDims) 00274 LFATAL("invalid image dimensions (got %dx%d, expected %dx%d)", 00275 f.getDims().w(), f.getDims().h(), itsDims.w(), itsDims.h()); 00276 00277 switch (itsVideoFormat) 00278 { 00279 case VIDFMT_UYVY: 00280 case VIDFMT_YUV422: 00281 case VIDFMT_YUV420P: 00282 if (f.getMode() != itsVideoFormat) 00283 LFATAL("input frame in wrong format (expected %s, got %s)", 00284 convertToString(itsVideoFormat).c_str(), 00285 convertToString(f.getMode()).c_str()); 00286 00287 itsSubprocess->out_stream() 00288 .write(reinterpret_cast<const char*>(f.getBuffer()), 00289 f.getBufSize()); 00290 00291 break; 00292 00293 default: 00294 { 00295 const Image<PixRGB<byte> > rgb = f.toRgb(); 00296 PnmWriter::writeRGB(rgb, itsSubprocess->out_stream()); 00297 } 00298 } 00299 00300 if (itsSubprocess->out_stream().fail()) 00301 LFATAL("pipe stream error while sending frame"); 00302 } 00303 00304 void UcbMpegEncoder::writeFrame(const GenericFrame& f) 00305 { 00306 this->writeVideoFrame(f.asVideo()); 00307 } 00308 00309 // ###################################################################### 00310 /* So things look consistent in everyone's emacs... */ 00311 /* Local Variables: */ 00312 /* mode: c++ */ 00313 /* indent-tabs-mode: nil */ 00314 /* End: */ 00315 00316 #endif // MEDIA_UCBMPEGENCODER_C_DEFINED