00001 /*!@file Media/FrameSeries.C a series of frames */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 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@klab.caltech.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Media/FrameSeries.C $ 00035 // $Id: FrameSeries.C 14559 2011-03-01 22:02:47Z ehu $ 00036 // 00037 00038 #include <cstddef> 00039 #include <vector> 00040 00041 #include "Component/GlobalOpts.H" // for OPT_TestMode 00042 #include "Component/ModelOptionDef.H" 00043 #include "Component/OptionManager.H" 00044 #include "Component/Plugin.H" 00045 #include "Devices/DC1394Grabber2.H" 00046 #include "Devices/DiskDataStream.H" 00047 #include "Devices/IEEE1394grabber.H" 00048 #include "Devices/QuickTimeGrabber.H" 00049 #include "Devices/RTSPGrabber.H" 00050 #include "Devices/V4L2grabber.H" 00051 #include "Devices/V4Lgrabber.H" 00052 #include "Devices/KinectGrabber.H" 00053 #include "Devices/OpenNIGrabber.H" 00054 #include "GUI/ImageDisplayStream.H" 00055 00056 #include "Devices/XCgrabber.H" 00057 #include "Devices/XCgrabberFlex.H" 00058 #include "Media/FrameSeries.H" 00059 00060 #ifdef INVT_HAVE_QT4 00061 # include "GUI/QtDisplayStream4.H" // use the Qt4 version of QtDisplayStream if we have Qt4 installed 00062 #else 00063 #ifdef INVT_HAVE_QT3 00064 # include "GUI/QtDisplayStream.H" 00065 #endif 00066 #endif 00067 00068 #include "GUI/SDLdisplayStream.H" 00069 #include "Image/CutPaste.H" // for inplaceEmbed() 00070 #include "Image/Image.H" 00071 #include "Image/Layout.H" 00072 #include "Image/Pixels.H" 00073 #include "Image/ShapeOps.H" // for rescale() 00074 #include "Media/FrameCounter.H" 00075 #include "Media/MediaOpts.H" 00076 #include "Media/MgzInputStream.H" 00077 #include "Media/MgzJInputStream.H" 00078 #include "Media/MgzOutputStream.H" 00079 #include "Media/MgzJOutputStream.H" 00080 #include "Media/MpegInputStream.H" 00081 #include "Media/MpegOutputStream.H" 00082 #include "Media/HttpOutputStream.H" 00083 #include "Media/MrawvInputStream.H" 00084 #include "Media/MrawvOutputStream.H" 00085 #include "Media/NullOutputStream.H" 00086 #include "Media/SequenceFileStream.H" 00087 #include "Media/UcbMpegOutputStream.H" 00088 #include "Raster/GenericFrame.H" 00089 #include "Transport/BobDeinterlacer.H" 00090 #include "Transport/BufferedFrameIstream.H" 00091 #include "Transport/CoerceVideoFormatOfilt.H" 00092 #include "Transport/ColorbarsInput.H" 00093 #include "Transport/ColorizeOfilt.H" 00094 #include "Transport/FrameInfo.H" 00095 #include "Transport/FrameIstreamFactory.H" 00096 #include "Transport/FrameOstreamFactory.H" 00097 #include "Transport/GameOfLifeInput.H" 00098 #include "Transport/HalfFieldDeinterlacer.H" 00099 #include "Transport/HashOutputSeries.H" 00100 #include "Transport/InfoOutputSeries.H" 00101 #include "Transport/LuminanceOfilt.H" 00102 #include "Transport/RandomInput.H" 00103 #include "Transport/DotStimuli.H" 00104 #include "Transport/BarStimuli.H" 00105 #include "Transport/ShiftedImage.H" 00106 #include "Transport/RasterInputSeries.H" 00107 #include "Transport/RasterOutputSeries.H" 00108 #include "Transport/RasterlistInputSeries.H" 00109 #include "Transport/SplitRgbOfilt.H" 00110 #include "Transport/StatsOutputSeries.H" 00111 #include "Transport/TransportOpts.H" 00112 #include "Transport/World2DInput.H" 00113 #include "Transport/World3DInput.H" 00114 #include "Transport/XMLInput.H" 00115 #include "Transport/Stimulus2D.H" 00116 #include "Util/AllocAux.H" // for invt_allocation_set_stats_units() 00117 #include "Util/TextLog.H" 00118 #include "Util/log.H" 00119 #include "Util/sformat.H" 00120 00121 // Private command-line option defs 00122 00123 namespace 00124 { 00125 bool isRectEmpty(const Rectangle& rect) 00126 { 00127 return 00128 (rect.isValid() == false) 00129 || 00130 (rect.area() == 0); 00131 } 00132 00133 template <class T> 00134 Image<T> doResizeImage(const Image<T>& input, 00135 const Rectangle& rect, 00136 const Dims& dims, 00137 const int zoom, 00138 const bool preserveAspect) 00139 { 00140 // if we got an empty image, that means we're at the end of our 00141 // input stream and so we just pass along the empty image as is: 00142 if (!input.initialized()) return input; 00143 00144 if (dims.isEmpty() && zoom == 0) return input; 00145 00146 Image<T> cropped = input; 00147 00148 if (!isRectEmpty(rect)) 00149 { 00150 cropped = crop(input, rect, true); 00151 } 00152 00153 if (zoom < 0) 00154 { 00155 const Dims zoomout(std::max(cropped.getWidth() >> (-zoom), 1), 00156 std::max(cropped.getHeight() >> (-zoom), 1)); 00157 00158 cropped = rescale(cropped, zoomout); 00159 } 00160 else if (zoom > 0) 00161 { 00162 cropped = zoomXY(cropped, 1 << zoom, 1 << zoom); 00163 } 00164 00165 if (preserveAspect) 00166 { 00167 Image<T> res(dims, ZEROS); 00168 T bg = T(); bg += 64; 00169 inplaceEmbed(res, cropped, res.getBounds(), bg, true); 00170 return res; 00171 } 00172 00173 if (dims.isNonEmpty()) 00174 return rescale(cropped, dims); 00175 00176 return cropped; 00177 } 00178 00179 GenericFrame doResizeFrame(const GenericFrame& input, 00180 const Rectangle& rect, 00181 const Dims& dims, 00182 const int zoom, 00183 const bool preserveAspect) 00184 { 00185 /* Check if we can skip resizing altogether and just return a copy 00186 of the original image. 00187 00188 NOTE that this check is critical in allowing efficient 00189 optimizations based on representations that would are lost when 00190 we are forced to resize. For example, SDLdisplayStream is 00191 optimized for displaying YUV VideoFrame objects, and 00192 ImageDisplayStream is optimized for displaying Layout 00193 objects. When we are forced to resize a VideoFrame or Layout, 00194 those optimizations are lost because the frame has to be 00195 rendered as a plain Image before resizing. 00196 */ 00197 if (zoom == 0 00198 && (dims.isEmpty() || dims == input.getDims()) 00199 && !preserveAspect) 00200 return input; 00201 00202 switch (input.nativeType()) 00203 { 00204 case GenericFrame::NONE: 00205 return GenericFrame(); 00206 00207 case GenericFrame::RGB_U8: 00208 return GenericFrame(doResizeImage(input.asRgbU8(), 00209 rect, dims, zoom, preserveAspect)); 00210 00211 case GenericFrame::RGBD: 00212 return GenericFrame(doResizeImage(input.asRgbU8(), rect, dims, zoom, preserveAspect), 00213 doResizeImage(input.asGrayU16(), rect, dims, zoom, preserveAspect)); 00214 00215 case GenericFrame::RGB_F32: 00216 return GenericFrame(doResizeImage(input.asRgbF32(), 00217 rect, dims, zoom, preserveAspect), 00218 input.floatFlags()); 00219 00220 case GenericFrame::GRAY_U8: 00221 return GenericFrame(doResizeImage(input.asGrayU8(), 00222 rect, dims, zoom, preserveAspect)); 00223 00224 case GenericFrame::GRAY_F32: 00225 return GenericFrame(doResizeImage(input.asGrayF32(), 00226 rect, dims, zoom, preserveAspect), 00227 input.floatFlags()); 00228 00229 case GenericFrame::VIDEO: 00230 // NOTE: if we are going to resize a VideoFrame, we'll first 00231 // have to convert it to rgb and do the resizing in that 00232 // format 00233 return GenericFrame(doResizeImage(input.asRgb(), 00234 rect, dims, zoom, preserveAspect)); 00235 00236 case GenericFrame::RGB_U16: 00237 return GenericFrame(); break; 00238 case GenericFrame::GRAY_U16: 00239 return GenericFrame(); break; 00240 00241 } 00242 00243 ASSERT(0); /* can't happen */ return GenericFrame(); 00244 } 00245 00246 // this is a file-global variable that is needed when we use 00247 // pthread_once() to initialize the factories with istream_init() 00248 // and ostream_init(); those init functions need an OptionManager to 00249 // do the initialization but pthread_once() doesn't allow any args 00250 // to be passed to the init function, thus we have to communicate 00251 // the args through an outside variable 00252 OptionManager* init_manager = 0; 00253 00254 pthread_once_t istream_init_once = PTHREAD_ONCE_INIT; 00255 00256 void istream_init() 00257 { 00258 ASSERT(init_manager != 0); 00259 00260 OptionManager& mgr = *init_manager; 00261 00262 ComponentFactory<FrameIstream>& inTypeFactory = getFrameIstreamTypeFactory(); 00263 00264 // NOTE: If you add input sources or otherwise modify the 00265 // inTypeFactory, then please also update the documentation of the 00266 // main "--in" option in the definition of OPT_InputFrameSource in 00267 // Media/MediaOpts.C so that your changes will be visible to 00268 // users. 00269 00270 inTypeFactory.registerType<RasterInputSeries>("raster", mgr); 00271 inTypeFactory.registerType<RasterlistInputSeries>("rasterlist", mgr); 00272 inTypeFactory.registerType<InputMPEGStream>("mpeg", mgr); 00273 inTypeFactory.registerType<InputMPEGStream>("movie", mgr); 00274 inTypeFactory.registerType<RandomInput>("random", mgr); 00275 inTypeFactory.registerType<DotStimuli>("dots", mgr); 00276 inTypeFactory.registerType<BarStimuli>("bars", mgr); 00277 inTypeFactory.registerType<ShiftedImage>("shiftedImage", mgr); 00278 inTypeFactory.registerType<GameOfLifeInput>("life", mgr); 00279 inTypeFactory.registerType<World2DInput>("World2D", mgr); 00280 inTypeFactory.registerType<World3DInput>("World3D", mgr); 00281 inTypeFactory.registerType<Stimulus2D>("stimulus2D", mgr); 00282 inTypeFactory.registerType<XMLInput>("xmlfile", mgr); 00283 #ifdef HAVE_LINUX_VIDEODEV_H 00284 inTypeFactory.registerType<V4Lgrabber>("v4l", mgr); 00285 #endif 00286 #ifdef HAVE_LINUX_VIDEODEV2_H 00287 inTypeFactory.registerType<V4L2grabber>("v4l2", mgr); 00288 #endif 00289 inTypeFactory.registerType<IEEE1394grabber>("ieee1394", mgr); 00290 #ifdef HAVE_XCLIB 00291 inTypeFactory.registerType<XCgrabber>("XC", mgr); 00292 #endif 00293 #ifdef HAVE_XCLIB 00294 inTypeFactory.registerType<XCgrabberFlex>("XCFLEX", mgr); 00295 #endif 00296 inTypeFactory.registerType<DC1394Grabber2>("dc1394v2", mgr); 00297 inTypeFactory.registerType<QuickTimeGrabber>("qtgrab", mgr); 00298 #ifdef INVT_HAVE_LIBFREENECT 00299 inTypeFactory.registerType<KinectGrabber>("kinect", mgr); 00300 #endif 00301 #ifdef INVT_HAVE_OPENNI 00302 inTypeFactory.registerType<OpenNIGrabber>("openni", mgr); 00303 #endif 00304 inTypeFactory.registerType<RTSPGrabber>("rtsp", mgr); 00305 inTypeFactory.registerType<ColorbarsInput>("colorbars", mgr); 00306 inTypeFactory.registerType<BobDeinterlacer>("bob", mgr); 00307 inTypeFactory.registerType<HalfFieldDeinterlacer<true> >("bhf", mgr); 00308 inTypeFactory.registerType<HalfFieldDeinterlacer<false> >("thf", mgr); 00309 inTypeFactory.registerType<MgzInputStream>("mgz", mgr); 00310 inTypeFactory.registerType<MgzJInputStream>("mgzJ", mgr); 00311 inTypeFactory.registerType<BufferedFrameIstream>("buf", mgr); 00312 inTypeFactory.registerType<MrawvInputStream>("mraw", mgr); 00313 00314 inTypeFactory.set_fallback 00315 (rutz::make_shared(new PluginFallback(init_manager, "FrameIstream"))); 00316 00317 ComponentFactory<FrameIstream>& inExtFactory = getFrameIstreamExtFactory(); 00318 00319 // NOTE: If you add input sources or otherwise modify the 00320 // inExtFactory, then please also update the documentation of the 00321 // main "--in" option in the definition of OPT_InputFrameSource in 00322 // Media/MediaOpts.C so that your changes will be visible to 00323 // users. 00324 00325 inExtFactory.registerType<RasterInputSeries>("pnm", mgr); // RASFMT_PNM 00326 inExtFactory.registerType<RasterInputSeries>("pgm", mgr); // RASFMT_PNM 00327 inExtFactory.registerType<RasterInputSeries>("ppm", mgr); // RASFMT_PNM 00328 inExtFactory.registerType<RasterInputSeries>("pbm", mgr); // RASFMT_PNM 00329 inExtFactory.registerType<RasterInputSeries>("pfm", mgr); // RASFMT_PFM 00330 inExtFactory.registerType<RasterInputSeries>("png", mgr); // RASFMT_PNG 00331 inExtFactory.registerType<RasterInputSeries>("jpeg", mgr); // RASFMT_JPEG 00332 inExtFactory.registerType<RasterInputSeries>("jpg", mgr); // RASFMT_JPEG 00333 inExtFactory.registerType<RasterInputSeries>("dpx", mgr); // RASFMT_DPX 00334 00335 inExtFactory.registerType<RasterInputSeries>("grey", mgr); // RASFMT_RAW_VIDEO 00336 inExtFactory.registerType<RasterInputSeries>("rgb555", mgr); // RASFMT_RAW_VIDEO 00337 inExtFactory.registerType<RasterInputSeries>("rgb565", mgr); // RASFMT_RAW_VIDEO 00338 inExtFactory.registerType<RasterInputSeries>("rgb24", mgr); // RASFMT_RAW_VIDEO 00339 inExtFactory.registerType<RasterInputSeries>("rgb32", mgr); // RASFMT_RAW_VIDEO 00340 inExtFactory.registerType<RasterInputSeries>("yuv24", mgr); // RASFMT_RAW_VIDEO 00341 inExtFactory.registerType<RasterInputSeries>("yuyv", mgr); // RASFMT_RAW_VIDEO 00342 inExtFactory.registerType<RasterInputSeries>("uyvy", mgr); // RASFMT_RAW_VIDEO 00343 inExtFactory.registerType<RasterInputSeries>("yuv444", mgr); // RASFMT_RAW_VIDEO 00344 inExtFactory.registerType<RasterInputSeries>("yuv422", mgr); // RASFMT_RAW_VIDEO 00345 inExtFactory.registerType<RasterInputSeries>("yuv411", mgr); // RASFMT_RAW_VIDEO 00346 inExtFactory.registerType<RasterInputSeries>("yuv420", mgr); // RASFMT_RAW_VIDEO 00347 inExtFactory.registerType<RasterInputSeries>("yuv410", mgr); // RASFMT_RAW_VIDEO 00348 inExtFactory.registerType<RasterInputSeries>("yuv444p", mgr); // RASFMT_RAW_VIDEO 00349 inExtFactory.registerType<RasterInputSeries>("yuv422p", mgr); // RASFMT_RAW_VIDEO 00350 inExtFactory.registerType<RasterInputSeries>("yuv411p", mgr); // RASFMT_RAW_VIDEO 00351 inExtFactory.registerType<RasterInputSeries>("yuv420p", mgr); // RASFMT_RAW_VIDEO 00352 inExtFactory.registerType<RasterInputSeries>("yuv410p", mgr); // RASFMT_RAW_VIDEO 00353 00354 inExtFactory.registerType<RasterInputSeries>("grey.gz", mgr); // RASFMT_RAW_VIDEO 00355 inExtFactory.registerType<RasterInputSeries>("rgb555.gz", mgr); // RASFMT_RAW_VIDEO 00356 inExtFactory.registerType<RasterInputSeries>("rgb565.gz", mgr); // RASFMT_RAW_VIDEO 00357 inExtFactory.registerType<RasterInputSeries>("rgb24.gz", mgr); // RASFMT_RAW_VIDEO 00358 inExtFactory.registerType<RasterInputSeries>("rgb32.gz", mgr); // RASFMT_RAW_VIDEO 00359 inExtFactory.registerType<RasterInputSeries>("yuv24.gz", mgr); // RASFMT_RAW_VIDEO 00360 inExtFactory.registerType<RasterInputSeries>("yuyv.gz", mgr); // RASFMT_RAW_VIDEO 00361 inExtFactory.registerType<RasterInputSeries>("uyvy.gz", mgr); // RASFMT_RAW_VIDEO 00362 inExtFactory.registerType<RasterInputSeries>("yuv444.gz", mgr); // RASFMT_RAW_VIDEO 00363 inExtFactory.registerType<RasterInputSeries>("yuv422.gz", mgr); // RASFMT_RAW_VIDEO 00364 inExtFactory.registerType<RasterInputSeries>("yuv411.gz", mgr); // RASFMT_RAW_VIDEO 00365 inExtFactory.registerType<RasterInputSeries>("yuv420.gz", mgr); // RASFMT_RAW_VIDEO 00366 inExtFactory.registerType<RasterInputSeries>("yuv410.gz", mgr); // RASFMT_RAW_VIDEO 00367 inExtFactory.registerType<RasterInputSeries>("yuv444p.gz", mgr); // RASFMT_RAW_VIDEO 00368 inExtFactory.registerType<RasterInputSeries>("yuv422p.gz", mgr); // RASFMT_RAW_VIDEO 00369 inExtFactory.registerType<RasterInputSeries>("yuv411p.gz", mgr); // RASFMT_RAW_VIDEO 00370 inExtFactory.registerType<RasterInputSeries>("yuv420p.gz", mgr); // RASFMT_RAW_VIDEO 00371 inExtFactory.registerType<RasterInputSeries>("yuv410p.gz", mgr); // RASFMT_RAW_VIDEO 00372 00373 inExtFactory.registerType<RasterInputSeries>("grey.bz2", mgr); // RASFMT_RAW_VIDEO 00374 inExtFactory.registerType<RasterInputSeries>("rgb555.bz2", mgr); // RASFMT_RAW_VIDEO 00375 inExtFactory.registerType<RasterInputSeries>("rgb565.bz2", mgr); // RASFMT_RAW_VIDEO 00376 inExtFactory.registerType<RasterInputSeries>("rgb24.bz2", mgr); // RASFMT_RAW_VIDEO 00377 inExtFactory.registerType<RasterInputSeries>("rgb32.bz2", mgr); // RASFMT_RAW_VIDEO 00378 inExtFactory.registerType<RasterInputSeries>("yuv24.bz2", mgr); // RASFMT_RAW_VIDEO 00379 inExtFactory.registerType<RasterInputSeries>("yuyv.bz2", mgr); // RASFMT_RAW_VIDEO 00380 inExtFactory.registerType<RasterInputSeries>("uyvy.bz2", mgr); // RASFMT_RAW_VIDEO 00381 inExtFactory.registerType<RasterInputSeries>("yuv444.bz2", mgr); // RASFMT_RAW_VIDEO 00382 inExtFactory.registerType<RasterInputSeries>("yuv422.bz2", mgr); // RASFMT_RAW_VIDEO 00383 inExtFactory.registerType<RasterInputSeries>("yuv411.bz2", mgr); // RASFMT_RAW_VIDEO 00384 inExtFactory.registerType<RasterInputSeries>("yuv420.bz2", mgr); // RASFMT_RAW_VIDEO 00385 inExtFactory.registerType<RasterInputSeries>("yuv410.bz2", mgr); // RASFMT_RAW_VIDEO 00386 inExtFactory.registerType<RasterInputSeries>("yuv444p.bz2", mgr); // RASFMT_RAW_VIDEO 00387 inExtFactory.registerType<RasterInputSeries>("yuv422p.bz2", mgr); // RASFMT_RAW_VIDEO 00388 inExtFactory.registerType<RasterInputSeries>("yuv411p.bz2", mgr); // RASFMT_RAW_VIDEO 00389 inExtFactory.registerType<RasterInputSeries>("yuv420p.bz2", mgr); // RASFMT_RAW_VIDEO 00390 inExtFactory.registerType<RasterInputSeries>("yuv410p.bz2", mgr); // RASFMT_RAW_VIDEO 00391 00392 inExtFactory.registerType<InputMPEGStream>("avi", mgr); 00393 inExtFactory.registerType<InputMPEGStream>("mpg", mgr); 00394 inExtFactory.registerType<InputMPEGStream>("mpeg", mgr); 00395 inExtFactory.registerType<InputMPEGStream>("m4v", mgr); 00396 inExtFactory.registerType<InputMPEGStream>("mov", mgr); 00397 inExtFactory.registerType<InputMPEGStream>("flv", mgr); // Flash video, supported by ffmpeg 00398 inExtFactory.registerType<InputMPEGStream>("dv", mgr); 00399 inExtFactory.registerType<InputMPEGStream>("asf", mgr); 00400 inExtFactory.registerType<InputMPEGStream>("wmv", mgr); 00401 inExtFactory.registerType<InputMPEGStream>("m2ts", mgr); 00402 00403 inExtFactory.registerType<MgzInputStream>("mgz", mgr); 00404 inExtFactory.registerType<MgzJInputStream>("mgzJ", mgr); 00405 00406 inExtFactory.registerType<MrawvInputStream>("mgrey", mgr); 00407 inExtFactory.registerType<MrawvInputStream>("mrgb555", mgr); 00408 inExtFactory.registerType<MrawvInputStream>("mrgb565", mgr); 00409 inExtFactory.registerType<MrawvInputStream>("mrgb24", mgr); 00410 inExtFactory.registerType<MrawvInputStream>("mrgb32", mgr); 00411 inExtFactory.registerType<MrawvInputStream>("myuv24", mgr); 00412 inExtFactory.registerType<MrawvInputStream>("myuyv", mgr); 00413 inExtFactory.registerType<MrawvInputStream>("muyvy", mgr); 00414 inExtFactory.registerType<MrawvInputStream>("myuv444", mgr); 00415 inExtFactory.registerType<MrawvInputStream>("myuv422", mgr); 00416 inExtFactory.registerType<MrawvInputStream>("myuv411", mgr); 00417 inExtFactory.registerType<MrawvInputStream>("myuv420", mgr); 00418 inExtFactory.registerType<MrawvInputStream>("myuv410", mgr); 00419 inExtFactory.registerType<MrawvInputStream>("myuv444p", mgr); 00420 inExtFactory.registerType<MrawvInputStream>("myuv422p", mgr); 00421 inExtFactory.registerType<MrawvInputStream>("myuv411p", mgr); 00422 inExtFactory.registerType<MrawvInputStream>("myuv420p", mgr); 00423 inExtFactory.registerType<MrawvInputStream>("myuv410p", mgr); 00424 00425 inExtFactory.registerType<MrawvInputStream>("mgrey.gz", mgr); 00426 inExtFactory.registerType<MrawvInputStream>("mrgb555.gz", mgr); 00427 inExtFactory.registerType<MrawvInputStream>("mrgb565.gz", mgr); 00428 inExtFactory.registerType<MrawvInputStream>("mrgb24.gz", mgr); 00429 inExtFactory.registerType<MrawvInputStream>("mrgb32.gz", mgr); 00430 inExtFactory.registerType<MrawvInputStream>("myuv24.gz", mgr); 00431 inExtFactory.registerType<MrawvInputStream>("myuyv.gz", mgr); 00432 inExtFactory.registerType<MrawvInputStream>("muyvy.gz", mgr); 00433 inExtFactory.registerType<MrawvInputStream>("myuv444.gz", mgr); 00434 inExtFactory.registerType<MrawvInputStream>("myuv422.gz", mgr); 00435 inExtFactory.registerType<MrawvInputStream>("myuv411.gz", mgr); 00436 inExtFactory.registerType<MrawvInputStream>("myuv420.gz", mgr); 00437 inExtFactory.registerType<MrawvInputStream>("myuv410.gz", mgr); 00438 inExtFactory.registerType<MrawvInputStream>("myuv444p.gz", mgr); 00439 inExtFactory.registerType<MrawvInputStream>("myuv422p.gz", mgr); 00440 inExtFactory.registerType<MrawvInputStream>("myuv411p.gz", mgr); 00441 inExtFactory.registerType<MrawvInputStream>("myuv420p.gz", mgr); 00442 inExtFactory.registerType<MrawvInputStream>("myuv410p.gz", mgr); 00443 00444 inExtFactory.registerType<MrawvInputStream>("mgrey.bz2", mgr); 00445 inExtFactory.registerType<MrawvInputStream>("mrgb555.bz2", mgr); 00446 inExtFactory.registerType<MrawvInputStream>("mrgb565.bz2", mgr); 00447 inExtFactory.registerType<MrawvInputStream>("mrgb24.bz2", mgr); 00448 inExtFactory.registerType<MrawvInputStream>("mrgb32.bz2", mgr); 00449 inExtFactory.registerType<MrawvInputStream>("myuv24.bz2", mgr); 00450 inExtFactory.registerType<MrawvInputStream>("myuyv.bz2", mgr); 00451 inExtFactory.registerType<MrawvInputStream>("muyvy.bz2", mgr); 00452 inExtFactory.registerType<MrawvInputStream>("myuv444.bz2", mgr); 00453 inExtFactory.registerType<MrawvInputStream>("myuv422.bz2", mgr); 00454 inExtFactory.registerType<MrawvInputStream>("myuv411.bz2", mgr); 00455 inExtFactory.registerType<MrawvInputStream>("myuv420.bz2", mgr); 00456 inExtFactory.registerType<MrawvInputStream>("myuv410.bz2", mgr); 00457 inExtFactory.registerType<MrawvInputStream>("myuv444p.bz2", mgr); 00458 inExtFactory.registerType<MrawvInputStream>("myuv422p.bz2", mgr); 00459 inExtFactory.registerType<MrawvInputStream>("myuv411p.bz2", mgr); 00460 inExtFactory.registerType<MrawvInputStream>("myuv420p.bz2", mgr); 00461 inExtFactory.registerType<MrawvInputStream>("myuv410p.bz2", mgr); 00462 00463 inExtFactory.registerType<XMLInput>("xml", mgr); 00464 inExtFactory.registerType<SequenceFileStream>("seq", mgr); 00465 inExtFactory.registerType<Stimulus2D>("stim2d", mgr); 00466 } 00467 00468 pthread_once_t ostream_init_once = PTHREAD_ONCE_INIT; 00469 00470 void ostream_init() 00471 { 00472 ASSERT(init_manager != 0); 00473 00474 OptionManager& mgr = *init_manager; 00475 00476 ComponentFactory<FrameOstream>& outTypeFactory = getFrameOstreamTypeFactory(); 00477 00478 // NOTE: If you add output destinations or otherwise modify the 00479 // outTypeFactory, then please also update the documentation of 00480 // the main "--out" option in the definition of 00481 // OPT_OutputFrameSink in Media/MediaOpts.C so that your changes 00482 // will be visible to users. 00483 00484 outTypeFactory.registerType<GenericRasterOutputSeries>("raster", mgr); 00485 outTypeFactory.registerType<FixedRasterOutputSeries<RASFMT_PNM> >("pnm", mgr); 00486 outTypeFactory.registerType<FixedRasterOutputSeries<RASFMT_PNM> >("pgm", mgr); 00487 outTypeFactory.registerType<FixedRasterOutputSeries<RASFMT_PNM> >("ppm", mgr); 00488 outTypeFactory.registerType<FixedRasterOutputSeries<RASFMT_PNM> >("pbm", mgr); 00489 outTypeFactory.registerType<FixedRasterOutputSeries<RASFMT_PFM> >("pfm", mgr); 00490 outTypeFactory.registerType<FixedRasterOutputSeries<RASFMT_PNG> >("png", mgr); 00491 outTypeFactory.registerType<FixedRasterOutputSeries<RASFMT_RAW_VIDEO> >("rawvideo", mgr); 00492 outTypeFactory.registerType<FixedRasterOutputSeries<RASFMT_TXT> >("txt", mgr); 00493 outTypeFactory.registerType<FixedRasterOutputSeries<RASFMT_CCODE> >("ccode", mgr); 00494 00495 outTypeFactory.registerType<DiskDataStream>("bkg-rawvideo", mgr); 00496 00497 outTypeFactory.registerType<ImageDisplayStream>("display", mgr); 00498 #ifdef HAVE_SDL_SDL_H 00499 outTypeFactory.registerType<SDLdisplayStream>("sdl", mgr); 00500 #endif 00501 #if defined(INVT_HAVE_QT3) || defined(INVT_HAVE_QT4) 00502 outTypeFactory.registerType<QtDisplayStream>("qt", mgr); 00503 #endif 00504 #ifdef INVT_HAVE_AVCODEC 00505 outTypeFactory.registerType<OutputMPEGStream>("mpeg", mgr); 00506 outTypeFactory.registerType<OutputMPEGStream>("movie", mgr); 00507 outTypeFactory.registerType<OutputHttpStream>("http", mgr); 00508 #endif 00509 #ifdef MPEGENCODE_PROG 00510 outTypeFactory.registerType<UcbMpegOutputStream>("ucbmpeg", mgr); 00511 #endif 00512 outTypeFactory.registerType<HashOutputSeries>("hash", mgr); 00513 outTypeFactory.registerType<InfoOutputSeries>("info", mgr); 00514 outTypeFactory.registerType<StatsOutputSeries>("stats", mgr); 00515 outTypeFactory.registerType<MgzOutputStream>("mgz", mgr); 00516 outTypeFactory.registerType<MgzJOutputStream>("mgzJ", mgr); 00517 outTypeFactory.registerType<MrawvOutputStream>("mraw", mgr); 00518 outTypeFactory.registerType<NullOutputStream>("null", mgr); 00519 outTypeFactory.registerType<SplitRgbOfilt>("splitrgb", mgr); 00520 outTypeFactory.registerType<LuminanceOfilt>("luminance", mgr); 00521 outTypeFactory.registerType<ColorizeOfilt>("colorize", mgr); 00522 00523 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_GREY> >("coerce-grey", mgr); 00524 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_RGB555> >("coerce-rgb555", mgr); 00525 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_RGB565> >("coerce-rgb565", mgr); 00526 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_RGB24> >("coerce-rgb24", mgr); 00527 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_RGB32> >("coerce-rgb32", mgr); 00528 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUV24> >("coerce-yuv24", mgr); 00529 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUYV> >("coerce-yuyv", mgr); 00530 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_UYVY> >("coerce-uyvy", mgr); 00531 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUV444> >("coerce-yuv444", mgr); 00532 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUV422> >("coerce-yuv422", mgr); 00533 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUV411> >("coerce-yuv411", mgr); 00534 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUV444P> >("coerce-yuv444p", mgr); 00535 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUV422P> >("coerce-yuv422p", mgr); 00536 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUV411P> >("coerce-yuv411p", mgr); 00537 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUV420P> >("coerce-yuv420p", mgr); 00538 outTypeFactory.registerType<TCoerceVideoFormatOfilt<VIDFMT_YUV410P> >("coerce-yuv410p", mgr); 00539 00540 outTypeFactory.set_fallback 00541 (rutz::make_shared(new PluginFallback(init_manager, "FrameOstream"))); 00542 00543 ComponentFactory<FrameOstream>& outExtFactory = getFrameOstreamExtFactory(); 00544 00545 // NOTE: If you add output destinations or otherwise modify the 00546 // outExtFactory, then please also update the documentation of the 00547 // main "--out" option in the definition of OPT_OutputFrameSink in 00548 // Media/MediaOpts.C so that your changes will be visible to 00549 // users. 00550 00551 outExtFactory.registerType<FixedRasterOutputSeries<RASFMT_PNM> >("pnm", mgr); 00552 outExtFactory.registerType<FixedRasterOutputSeries<RASFMT_PNM> >("pgm", mgr); 00553 outExtFactory.registerType<FixedRasterOutputSeries<RASFMT_PNM> >("ppm", mgr); 00554 outExtFactory.registerType<FixedRasterOutputSeries<RASFMT_PNM> >("pbm", mgr); 00555 outExtFactory.registerType<FixedRasterOutputSeries<RASFMT_PFM> >("pfm", mgr); 00556 outExtFactory.registerType<FixedRasterOutputSeries<RASFMT_PNG> >("png", mgr); 00557 outExtFactory.registerType<FixedRasterOutputSeries<RASFMT_TXT> >("txt", mgr); 00558 outExtFactory.registerType<FixedRasterOutputSeries<RASFMT_CCODE> >("C", mgr); 00559 00560 #ifdef INVT_HAVE_AVCODEC 00561 outExtFactory.registerType<OutputMPEGStream>("mpg", mgr); 00562 outExtFactory.registerType<OutputMPEGStream>("mpeg", mgr); 00563 outExtFactory.registerType<OutputMPEGStream>("m4v", mgr); 00564 #endif 00565 00566 outExtFactory.registerType<MgzOutputStream>("mgz", mgr); 00567 outExtFactory.registerType<MgzJOutputStream>("mgzJ", mgr); 00568 } 00569 } 00570 00571 // ###################################################################### 00572 // #################### InputFrameSeries 00573 // ###################################################################### 00574 00575 struct InputFrameSeries::Impl 00576 { 00577 Impl(OptionManager& mgr, const FrameRange& range, bool wrap=false) 00578 : 00579 source(), 00580 sourceDescription(), 00581 echoes(), 00582 numEchoed(0), 00583 inputEof(false), 00584 lastUpdateTime(SimTime::ZERO()), 00585 counter(range, wrap) 00586 { 00587 } 00588 00589 nub::soft_ref<FrameIstream> source; 00590 std::string sourceDescription; 00591 std::vector<nub::ref<FrameOstream> > echoes; 00592 00593 int numEchoed; 00594 00595 bool inputEof; 00596 00597 SimTime lastUpdateTime; 00598 00599 FrameCounter counter; 00600 00601 bool setFrameNumber(int n) 00602 { 00603 //If our source doesn't allow us to seek, then don't mess 00604 //around with anything - just return false to the user. 00605 if(!this->source->supportsSeek() && this->counter.currentFrame() > n) return false; 00606 00607 return this->counter.setCurrent(n); 00608 } 00609 00610 // auxiliary implementation function around which readRGB(), 00611 // readGray(), readFloat() are thin wrappers 00612 GenericFrame readFrame(InputFrameSeries* self) 00613 { 00614 // double check we have a valid source 00615 ASSERT(this->source.is_valid()); 00616 00617 const int fnum = this->counter.currentFrame(); 00618 if (this->source->setFrameNumber(fnum)) 00619 { 00620 const GenericFrame ima = 00621 doResizeFrame(this->source->readFrame(), 00622 self->itsCropRect.getVal(), 00623 self->itsDims.getVal(), 00624 /* zoom */ 0, 00625 self->itsPreserveAspect.getVal()); 00626 00627 if (ima.initialized()) 00628 { 00629 LDEBUG("%s frame %d at %.2fms", 00630 self->tagName().c_str(), fnum, 00631 this->lastUpdateTime.msecs()); 00632 00633 textLog(self->itsLogFile.getVal(), 00634 self->tagName().c_str(), 00635 sformat("frame %d", fnum), 00636 this->lastUpdateTime); 00637 00638 // send the image out to all echo destinations: 00639 for (uint i = 0; i < this->echoes.size(); ++i) 00640 { 00641 this->echoes[i]->setFrameNumber(fnum); 00642 this->echoes[i]->writeFrame 00643 (ima, "input-echo", 00644 FrameInfo("copy of input frame", SRC_POS)); 00645 ++this->numEchoed; 00646 } 00647 00648 // set the default stats units so that it will be 00649 // available for later display of memory stats: 00650 invt_allocation_set_stats_units(ima.frameSpec().dims.sz()); 00651 00652 return ima; 00653 } 00654 else 00655 LINFO("input exhausted (readFrame() returned empty)"); 00656 } 00657 else 00658 LINFO("input exhausted (setFrameNumber() returned false)"); 00659 00660 // something failed, so we're at eof; now keep track of whether 00661 // we've hit eof, so that we can use that information in update() 00662 this->inputEof = true; 00663 00664 return GenericFrame(); 00665 } 00666 }; 00667 00668 InputFrameSeries::InputFrameSeries(OptionManager& mgr, 00669 const std::string& descrName, 00670 const std::string& tag) : 00671 FrameIstream(mgr, "Input "+descrName, "Input"+tag), 00672 itsLogFile(&OPT_TextLogFile, this), 00673 itsTestMode(&OPT_TestMode, this), 00674 itsFrameRange(&OPT_InputFrameRange, this), 00675 itsFrameWrap(&OPT_InputFramesWrap, this), 00676 itsCropRect(&OPT_InputFrameCrop, this), 00677 itsDims(&OPT_InputFrameDims, this), 00678 itsPreserveAspect(&OPT_InputPreserveAspect, this), 00679 itsZeroNumberFrames(&OPT_ZeroNumberFrames, this), 00680 itsFrameSource(&OPT_InputFrameSource, this), 00681 itsInOut(&OPT_InputOutputComboSpec, this), 00682 itsInputEcho(&OPT_InputEchoDest, this), 00683 itsWaitForUser(&OPT_WaitForUser, this), 00684 itsKeepGoing(&OPT_KeepGoing, this), 00685 rep(new Impl(mgr, itsFrameRange.getVal(), itsFrameWrap.getVal())) 00686 { 00687 init_manager = &mgr; 00688 pthread_once(&istream_init_once, &istream_init); 00689 pthread_once(&ostream_init_once, &ostream_init); 00690 } 00691 00692 // ###################################################################### 00693 InputFrameSeries::~InputFrameSeries() 00694 { 00695 delete rep; 00696 } 00697 00698 // ###################################################################### 00699 void InputFrameSeries::reset1() 00700 { 00701 // reset some stuff for FrameSeries 00702 rep->counter.reset(itsFrameRange.getVal(), false, itsFrameWrap.getVal()); 00703 rep->numEchoed = 0; 00704 rep->inputEof = false; 00705 00706 // propagate to our base class: 00707 FrameIstream::reset1(); 00708 } 00709 00710 00711 // ###################################################################### 00712 void InputFrameSeries::setFrameDims(Dims d) 00713 { 00714 OptionManager& mgr = getManager(); 00715 mgr.setOptionValString(&OPT_InputFrameDims, 00716 convertToString(d)); 00717 } 00718 00719 // ###################################################################### 00720 Dims InputFrameSeries::getFrameDims() 00721 { 00722 return itsDims.getVal(); 00723 } 00724 00725 00726 00727 // ###################################################################### 00728 void InputFrameSeries::paramChanged(ModelParamBase* const param, 00729 const bool valueChanged, 00730 ParamClient::ChangeStatus* status) 00731 { 00732 FrameIstream::paramChanged(param, valueChanged, status); 00733 00734 if (param == &itsFrameSource) 00735 { 00736 if (itsFrameSource.getVal() != "") 00737 this->setFrameSource(itsFrameSource.getVal()); 00738 } 00739 else if (param == &itsInOut) 00740 { 00741 if (itsInOut.getVal() != "") 00742 this->setFrameSource(itsInOut.getVal()); 00743 } 00744 else if (param == &itsInputEcho) 00745 { 00746 OptionManager& mgr = getManager(); 00747 00748 if (itsInputEcho.getVal() == "") 00749 { 00750 // ignore 00751 } 00752 else if (itsInputEcho.getVal() == "none") 00753 { 00754 rep->echoes.clear(); 00755 } 00756 else 00757 { 00758 nub::ref<FrameOstream> f = makeFrameOstream(itsInputEcho.getVal(), mgr); 00759 00760 rep->echoes.push_back(f); 00761 this->addSubComponent(f); 00762 f->exportOptions(MC_RECURSE); 00763 } 00764 } 00765 else if (param == &itsFrameRange) 00766 { 00767 rep->counter.reset(itsFrameRange.getVal(), false); 00768 } 00769 } 00770 00771 // ###################################################################### 00772 FrameState InputFrameSeries::update(const SimTime& stime) 00773 { 00774 00775 // check if we've hit eof, and handle it accordingly 00776 if (rep->inputEof) 00777 { 00778 if (itsKeepGoing.getVal()) 00779 // ok, user wants to keep going even though we're out of input 00780 return FRAME_SAME; 00781 else 00782 // default case is to quit when we're out of input 00783 return FRAME_COMPLETE; 00784 } 00785 00786 rep->numEchoed = 0; 00787 00788 rep->lastUpdateTime = stime; 00789 00790 const FrameState result = rep->counter.update(stime); 00791 00792 if (result != FRAME_SAME) 00793 { 00794 const int fnum = rep->counter.currentFrame(); 00795 00796 LDEBUG("%s frame %d at %.2fms", 00797 rep->source->tagName().c_str(), fnum, stime.msecs()); 00798 } 00799 00800 return result; 00801 } 00802 00803 // ###################################################################### 00804 FrameState InputFrameSeries::updateNext() 00805 { 00806 return rep->counter.updateNext(); 00807 } 00808 00809 // ###################################################################### 00810 bool InputFrameSeries::shouldWait() const 00811 { 00812 return rep->numEchoed > 0 00813 && itsWaitForUser.getVal() == true 00814 && !itsTestMode.getVal(); 00815 } 00816 00817 // ###################################################################### 00818 void InputFrameSeries::start1() 00819 { 00820 if (!rep->source.is_valid()) 00821 { 00822 LFATAL("\n\tOops, you didn't specify an input frame source.\n" 00823 "\tFor example, you can use --in=raster:path/to/filestem,\n" 00824 "\tor --in=mpeg:path/to/file.mpg, or --in=random:256x256."); 00825 } 00826 00827 rep->counter.reset(itsFrameRange.getVal(), false, itsFrameWrap.getVal()); 00828 00829 const int fnum = rep->counter.currentFrame(); 00830 if (!rep->source->setFrameNumber(fnum)) 00831 LFATAL("couldn't initialize frame source %s to frame number %d", 00832 rep->sourceDescription.c_str(), fnum); 00833 00834 rep->inputEof = false; 00835 } 00836 00837 // ###################################################################### 00838 void InputFrameSeries::start2() 00839 { 00840 FrameIstream::start2(); 00841 00842 // get the fully cooked input frame dims (after possible resizing 00843 // and framing): 00844 const Dims indims = this->peekDims(); 00845 00846 OptionManager& mgr = getManager(); 00847 00848 00849 // Setting the command line option of dim-size here is hacky because 00850 // the dim size is now assumed to come from the user even *after* a 00851 // change of setFrameSource(). The dims from peekDims() should be used, 00852 // and NOT this option... However, I don't know exactly where this is 00853 // used yet, so I have an externally controlled fix of calling 00854 // setFrameDims(Dims()) before setFrameSource() to destroy 00855 // the value (and thus ignoring any user requests) 00856 // In reality this option must never be touched and peekDims() 00857 // exclusively used. -DFP 10152010 00858 // set the input dims if someone wants them but they are not set: 00859 Dims idim(0, 0); 00860 convertFromString(mgr.getOptionValString(&OPT_InputFrameDims), idim); 00861 if (idim.isEmpty()) 00862 mgr.setOptionValString(&OPT_InputFrameDims, 00863 convertToString(indims)); 00864 00865 ASSERT(rep->source.is_valid()); 00866 00867 //Grab a copy of the FrameRange from our actual input source to see if it 00868 //has any hard restrictions on the frames it can retrieve. If it does, then 00869 //create a union of the most restrictive of each of the parameters from the user 00870 //and the source. 00871 FrameRange repRng = rep->source->getFrameRange(); 00872 FrameRange usrRng = this->getFrameRange(); 00873 if(repRng != FrameRange()) 00874 { 00875 std::vector<SimTime> delayTimes(usrRng.numDelayTimes()); 00876 for(size_t i=0; i<usrRng.numDelayTimes(); i++) 00877 delayTimes.at(i) = usrRng.getDelayTime(i); 00878 00879 FrameRange newRange( 00880 repRng.getFirst() > usrRng.getFirst() ? repRng.getFirst() : usrRng.getFirst(), 00881 usrRng.getStep(), 00882 repRng.getLast() < usrRng.getLast() ? repRng.getLast() : usrRng.getLast(), 00883 delayTimes, 00884 usrRng.isEventTriggered() 00885 ); 00886 00887 rep->counter.reset(newRange, true); 00888 itsFrameRange.setVal(newRange); 00889 } 00890 00891 00892 00893 00894 const GenericFrameSpec origspec = rep->source->peekFrameSpec(); 00895 const GenericFrameSpec finalspec = this->peekFrameSpec(); 00896 00897 const std::string description = 00898 origspec == finalspec 00899 ? origspec.getDescription() 00900 : sformat("originally %s; converted to %s", 00901 origspec.getDescription().c_str(), 00902 finalspec.getDescription().c_str()); 00903 00904 LINFO("input frames: %s", description.c_str()); 00905 textLog(itsLogFile.getVal(), 00906 "InputDims", sformat("%dx%d", indims.w(), indims.h())); 00907 } 00908 00909 // ###################################################################### 00910 GenericFrameSpec InputFrameSeries::peekFrameSpec() 00911 { 00912 // double check we have a valid source 00913 ASSERT(rep->source.is_valid()); 00914 00915 const int fnum = rep->counter.currentFrame(); 00916 00917 if (!rep->source->setFrameNumber(fnum)) 00918 LFATAL("couldn't initialize frame source %s to frame number %d", 00919 rep->sourceDescription.c_str(), fnum); 00920 00921 const GenericFrameSpec origspec = rep->source->peekFrameSpec(); 00922 00923 GenericFrameSpec result = origspec; 00924 00925 // if we are doing resizing, our dims are the resized dims: 00926 if (itsDims.getVal().isNonEmpty()) 00927 result.dims = itsDims.getVal(); 00928 00929 // otherwise if we are cropping, our dims are the cropped dims: 00930 else if (!isRectEmpty(itsCropRect.getVal())) 00931 result.dims = itsCropRect.getVal().dims(); 00932 00933 // now, if the dims have changed, then a VideoFrame will decay to 00934 // Image<PixRGB<byte> > 00935 if (result.dims != origspec.dims 00936 && origspec.nativeType == GenericFrame::VIDEO) 00937 result.nativeType = GenericFrame::RGB_U8; 00938 00939 return result; 00940 } 00941 00942 // ###################################################################### 00943 void InputFrameSeries::startStream() 00944 { 00945 if (!this->started()) 00946 LFATAL("startStream() must not be called until after start()"); 00947 00948 // double check we have a valid source 00949 ASSERT(rep->source.is_valid()); 00950 00951 rep->source->startStream(); 00952 } 00953 00954 // ###################################################################### 00955 GenericFrame InputFrameSeries::readFrame() 00956 { 00957 if (!this->started()) 00958 LFATAL("readFrame() must not be called until after start()"); 00959 00960 return rep->readFrame(this); 00961 } 00962 00963 // ###################################################################### 00964 void InputFrameSeries::setFrameSource(const std::string& source) 00965 { 00966 nub::soft_ref<FrameIstream> in = 00967 makeFrameIstream(source); 00968 00969 if (!in.is_valid()) 00970 { 00971 LFATAL("unknown value for %s: '%s'\n\tvalid values are %s", 00972 itsFrameSource.getOptionDef()->longoptname, 00973 source.c_str(), 00974 itsFrameSource.getOptionDef()->validvals); 00975 } 00976 00977 if (rep->source.is_valid()) 00978 this->removeSubComponent(*rep->source); 00979 rep->source = in; 00980 rep->sourceDescription = source; 00981 this->addSubComponent(rep->source); 00982 rep->source->exportOptions(MC_RECURSE); 00983 } 00984 00985 // ###################################################################### 00986 int InputFrameSeries::frame() const 00987 { 00988 return rep->counter.currentFrame(); 00989 } 00990 00991 // ###################################################################### 00992 nub::ref<FrameIstream> InputFrameSeries::getFrameSource() const 00993 { 00994 if (!rep->source.is_valid()) 00995 LFATAL("Oops! I don't have any frame source"); 00996 00997 return rep->source; 00998 } 00999 01000 // ###################################################################### 01001 FrameRange InputFrameSeries::getFrameRange() const 01002 { 01003 return itsFrameRange.getVal(); 01004 } 01005 01006 // ###################################################################### 01007 bool InputFrameSeries::setFrameNumber(int n) 01008 { 01009 return rep->setFrameNumber(n); 01010 } 01011 01012 01013 // ###################################################################### 01014 // #################### OutputFrameSeries 01015 // ###################################################################### 01016 01017 struct OutputFrameSeries::Impl 01018 { 01019 Impl(OptionManager& mgr, const FrameRange& range) 01020 : 01021 vec(), 01022 explicitNone(false), 01023 counter(range), 01024 wasNonvoidAtStart(false) 01025 {} 01026 01027 typedef std::vector<nub::ref<FrameOstream> > VecType; 01028 01029 VecType vec; 01030 01031 // by default, we will treat an empty destination list as an error 01032 // (to prevent somebody spending lots of CPU time only to find out 01033 // that their results haven't gone anywhere); but, if the user 01034 // explicitly specifies --out=none, then we'll allow an empty 01035 // destination list 01036 bool explicitNone; 01037 01038 FrameCounter counter; 01039 01040 bool wasNonvoidAtStart; 01041 }; 01042 01043 OutputFrameSeries::OutputFrameSeries(OptionManager& mgr, 01044 const std::string& descrName, 01045 const std::string& tag) : 01046 FrameOstream(mgr, "Output " + descrName, "Output"+tag), 01047 itsLogFile(&OPT_TextLogFile, this), 01048 itsTestMode(&OPT_TestMode, this), 01049 itsFrameRange(&OPT_OutputFrameRange, this), 01050 itsDims(&OPT_OutputFrameDims, this), 01051 itsPreserveAspect(&OPT_OutputPreserveAspect, this), 01052 itsZoom(&OPT_OutputZoom, this), 01053 itsZeroNumberFrames(&OPT_ZeroNumberFrames, this), 01054 itsFrameSink(&OPT_OutputFrameSink, this), 01055 itsInOut(&OPT_InputOutputComboSpec, this), 01056 itsWaitForUser(&OPT_WaitForUser, this), 01057 itsOutputReplicate(&OPT_OutputReplicate, this), 01058 itsNumWritten(0), 01059 rep(new Impl(mgr, itsFrameRange.getVal())) 01060 { 01061 init_manager = &mgr; 01062 pthread_once(&istream_init_once, &istream_init); 01063 pthread_once(&ostream_init_once, &ostream_init); 01064 } 01065 01066 // ###################################################################### 01067 OutputFrameSeries::~OutputFrameSeries() 01068 { 01069 delete rep; 01070 } 01071 01072 // ###################################################################### 01073 void OutputFrameSeries::reset1() 01074 { 01075 // reset some stuff for FrameSeries 01076 rep->counter.reset(itsFrameRange.getVal(), true); 01077 itsNumWritten = 0; 01078 01079 rep->explicitNone = false; 01080 rep->vec.clear(); 01081 01082 // propagate to our base class: 01083 FrameOstream::reset1(); 01084 } 01085 01086 // ###################################################################### 01087 void OutputFrameSeries::paramChanged(ModelParamBase* const param, 01088 const bool valueChanged, 01089 ParamClient::ChangeStatus* status) 01090 { 01091 FrameOstream::paramChanged(param, valueChanged, status); 01092 01093 if (param == &itsFrameSink) 01094 { 01095 this->addFrameDest(itsFrameSink.getVal()); 01096 } 01097 else if (param == &itsInOut) 01098 { 01099 this->addFrameDest(itsInOut.getVal()); 01100 } 01101 else if (param == &itsFrameRange) 01102 { 01103 rep->counter.reset(itsFrameRange.getVal(), false); 01104 } 01105 } 01106 01107 // ###################################################################### 01108 FrameState OutputFrameSeries::update(const SimTime& stime, 01109 bool new_event) 01110 { 01111 // reset our itsNumWritten: 01112 itsNumWritten = 0; 01113 01114 const FrameState result = rep->counter.update(stime, new_event); 01115 01116 if (result != FRAME_SAME) 01117 { 01118 const int fnum = rep->counter.currentFrame(); 01119 01120 LDEBUG("%-20s frame %d at %.2fms", 01121 this->tagName().c_str(), fnum, stime.msecs()); 01122 01123 textLog(itsLogFile.getVal(), 01124 this->tagName().c_str(), 01125 sformat("frame %d", fnum), stime); 01126 } 01127 01128 return result; 01129 } 01130 01131 // ###################################################################### 01132 FrameState OutputFrameSeries::updateNext() 01133 { 01134 return rep->counter.updateNext(); 01135 } 01136 01137 // ###################################################################### 01138 bool OutputFrameSeries::shouldWait() const 01139 { 01140 return itsNumWritten > 0 01141 && itsWaitForUser.getVal() == true 01142 && !itsTestMode.getVal(); 01143 } 01144 01145 // ###################################################################### 01146 void OutputFrameSeries::writeFrame(const GenericFrame& orig, 01147 const std::string& shortname, 01148 const FrameInfo& auxinfo) 01149 { 01150 int fnum; 01151 if(itsZeroNumberFrames.getVal()) 01152 fnum = 0; 01153 else 01154 fnum = rep->counter.currentFrame(); 01155 01156 const GenericFrame frame = 01157 doResizeFrame(orig, Rectangle(), itsDims.getVal(), 01158 itsZoom.getVal(), itsPreserveAspect.getVal()); 01159 01160 // double-check that we avoid a silently empty output vector 01161 ASSERT(rep->vec.size() > 0 || rep->explicitNone); 01162 01163 for (size_t i = 0; i < rep->vec.size(); ++i) 01164 { 01165 for (size_t k = 0; k < itsOutputReplicate.getVal(); ++k) 01166 { 01167 rep->vec[i]->setFrameNumber(k + fnum * itsOutputReplicate.getVal()); 01168 rep->vec[i]->writeFrame(frame, shortname, auxinfo); 01169 } 01170 ++itsNumWritten; 01171 } 01172 } 01173 01174 // ###################################################################### 01175 bool OutputFrameSeries::isVoid() const 01176 { 01177 // look for any non-void child streams: 01178 for (size_t i = 0; i < rep->vec.size(); ++i) 01179 if (!rep->vec[i]->isVoid()) 01180 return false; 01181 01182 // no child streams were non-void, so we are void: 01183 return true; 01184 } 01185 01186 // ###################################################################### 01187 bool OutputFrameSeries::becameVoid() const 01188 { 01189 return rep->wasNonvoidAtStart && this->isVoid(); 01190 } 01191 01192 // ###################################################################### 01193 void OutputFrameSeries::closeStream(const std::string& shortname) 01194 { 01195 for (size_t i = 0; i < rep->vec.size(); ++i) 01196 rep->vec[i]->closeStream(shortname); 01197 } 01198 01199 // ###################################################################### 01200 void OutputFrameSeries::addFrameDest(const std::string& source) 01201 { 01202 if (source == "") 01203 return; 01204 01205 OptionManager& mgr = getManager(); 01206 01207 if (source == "none") 01208 { 01209 // get rid of any output destinations we may have already 01210 // created: 01211 while (rep->vec.size() != 0) 01212 { 01213 nub::ref<FrameOstream> f = rep->vec.back(); 01214 rep->vec.pop_back(); 01215 this->removeSubComponent(*f); 01216 } 01217 rep->explicitNone = true; 01218 } 01219 else 01220 { 01221 nub::ref<FrameOstream> f = makeFrameOstream(source, mgr); 01222 01223 rep->vec.push_back(f); 01224 this->addSubComponent(f); 01225 f->exportOptions(MC_RECURSE); 01226 } 01227 } 01228 01229 // ###################################################################### 01230 size_t OutputFrameSeries::getNumFrameDests() const 01231 { 01232 return rep->vec.size(); 01233 } 01234 01235 // ###################################################################### 01236 nub::ref<FrameOstream> OutputFrameSeries::getFrameDest(size_t n) const 01237 { 01238 ASSERT(n < rep->vec.size()); 01239 01240 return rep->vec[n]; 01241 } 01242 01243 // ###################################################################### 01244 void OutputFrameSeries::start2() 01245 { 01246 rep->counter.reset(itsFrameRange.getVal(), true); 01247 01248 if (rep->vec.empty() && !rep->explicitNone) 01249 LFATAL("\n\tOops, you didn't specify an output destination with\n" 01250 "\tan --out option. If this is actually the behavior\n" 01251 "\tyou want, you can do an explicit --out=none to avoid\n" 01252 "\tthis error message. Otherwise, you can use an option\n" 01253 "\tlike --out=raster:path/to/filestem or --out=mpeg:\n" 01254 "\tor --out=display: to request particular output format."); 01255 01256 rep->wasNonvoidAtStart = !this->isVoid(); 01257 } 01258 01259 // ###################################################################### 01260 int OutputFrameSeries::frame() const 01261 { 01262 if(itsZeroNumberFrames.getVal()) 01263 return 0; 01264 else 01265 return rep->counter.currentFrame(); 01266 } 01267 01268 01269 // ###################################################################### 01270 /* So things look consistent in everyone's emacs... */ 01271 /* Local Variables: */ 01272 /* indent-tabs-mode: nil */ 01273 /* End: */