1 /* ***** BEGIN LICENSE BLOCK ***** 2 * This file is part of openfx-io <https://github.com/MrKepzie/openfx-io>, 3 * Copyright (C) 2013-2018 INRIA 4 * 5 * openfx-io is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * openfx-io is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with openfx-io. If not, see <http://www.gnu.org/licenses/gpl-2.0.html> 17 * ***** END LICENSE BLOCK ***** */ 18 19 /* 20 * OFX GenericReader plugin. 21 * A base class for all OpenFX-based decoders. 22 */ 23 24 #ifndef Io_GenericReader_h 25 #define Io_GenericReader_h 26 27 #include <memory> 28 #include <ofxsImageEffect.h> 29 #include <ofxsMacros.h> 30 #include "IOUtility.h" 31 32 namespace SequenceParsing { 33 class SequenceFromFiles; 34 } 35 36 NAMESPACE_OFX_ENTER 37 NAMESPACE_OFX_IO_ENTER 38 39 #ifdef OFX_IO_USING_OCIO 40 class GenericOCIO; 41 #endif 42 43 /** 44 * @brief A generic reader plugin, derive this to create a new reader for a specific file format. 45 * This class propose to handle the common stuff among readers: 46 * - common params 47 * - a tiny cache to speed-up the successive getRegionOfDefinition() calls 48 * - a way to inform the host about the colour-space of the data. 49 **/ 50 class GenericReaderPlugin 51 : public OFX::ImageEffect 52 { 53 public: 54 55 GenericReaderPlugin(OfxImageEffectHandle handle, 56 const std::vector<std::string>& extensions, 57 bool supportsTiles, 58 bool supportsRGBA, 59 bool supportsRGB, 60 bool supportsXY, 61 bool supportsAlpha, 62 bool isMultiPlanar); 63 64 virtual ~GenericReaderPlugin(); 65 66 /** 67 * @brief Don't override this function, the GenericReaderPlugin class already does the rendering. The "decoding" of the frame 68 * must be done by the pure virtual function decode(...) instead. 69 **/ 70 virtual void render(const OFX::RenderArguments &args) OVERRIDE FINAL; 71 72 /** 73 * @brief Don't override this. Basically this function will call getTimeDomainForVideoStream(...), 74 * which your reader should implement to read from a video-stream the time range. 75 * If the file is not a video stream, the function getTimeDomainForVideoStream() should return false, indicating that 76 * we're reading a sequence of images and that the host should get the time domain for us. 77 **/ 78 virtual bool getTimeDomain(OfxRangeD &range) OVERRIDE FINAL; 79 80 /** 81 * @brief Don't override this. If the pure virtual function areHeaderAndDataTied() returns true, this 82 * function will call decode() to read the region of definition of the image and cache away the decoded image 83 * into the _dstImg member. 84 * If areHeaderAndDataTied() returns false instead, this function will call the virtual function 85 * getFrameBounds() which should read the header of the image to only extract the bounds and PAR of the image. 86 **/ 87 virtual bool getRegionOfDefinition(const OFX::RegionOfDefinitionArguments &args, OfxRectD &rod) OVERRIDE FINAL; 88 89 90 /** 91 * @brief You can override this to take actions in response to a param change. 92 * Make sure you call the base-class version of this function at the end: i.e: 93 * 94 * void MyReader::changedParam(const OFX::InstanceChangedArgs &args, const std::string ¶mName) { 95 * if (.....) { 96 * 97 * } else if(.....) { 98 * 99 * } else { 100 * GenericReaderPlugin::changedParam(args,paramName); 101 * } 102 * } 103 **/ 104 virtual void changedParam(const OFX::InstanceChangedArgs &args, const std::string ¶mName) OVERRIDE; 105 106 /* override is identity */ 107 virtual bool isIdentity(const OFX::IsIdentityArguments &args, OFX::Clip * &identityClip, double &identityTime, int& view, std::string& plane) OVERRIDE; 108 109 /** 110 * @brief Set the output components and premultiplication state for the input image automatically. 111 * This is filled from directly the info returned by guessParamsFromFilename 112 **/ 113 virtual void getClipPreferences(OFX::ClipPreferencesSetter &clipPreferences) OVERRIDE; 114 115 /** 116 * @brief Overriden to clear any OCIO cache. 117 * This function calls clearAnyCache() if you have any cache to clear. 118 **/ 119 virtual void purgeCaches(void) OVERRIDE; 120 121 /** 122 * @brief Restore any state from the parameters set 123 * Called from createInstance() and changedParam() (via changedFilename()), must restore the 124 * state of the Reader, such as Choice param options, data members and non-persistent param values. 125 * We don't do this in the ctor of the plug-in since we can't call virtuals yet. 126 * Any derived implementation must call GenericReaderPlugin::restoreStateFromParams() first 127 **/ 128 virtual void restoreStateFromParams(); 129 130 isMultiPlanar()131 bool isMultiPlanar() const 132 { 133 return _isMultiPlanar; 134 } 135 136 enum BeforeAfterEnum 137 { 138 eBeforeAfterHold, 139 eBeforeAfterLoop, 140 eBeforeAfterBounce, 141 eBeforeAfterBlack, 142 eBeforeAfterError, 143 }; 144 145 protected: 146 /** 147 * @brief Called from changedParam() when kParamFilename is changed for any reason other than eChangeTime. 148 * Calls restoreStateFromParams() to update any non-persistent params that may depend on the filename. 149 * If reason is eChangeUserEdit and the params where never guessed (see _guessedParams) also sets these from the file contents. 150 * Any derived implementation must call GenericReaderPlugin::changedFilename() first 151 **/ 152 virtual void changedFilename(const OFX::InstanceChangedArgs &args); 153 154 155 OFX::ChoiceParam* _missingFrameParam; //< what to do on missing frame 156 157 OfxStatus getFilenameAtTime(double t, std::string *filename) const; 158 159 int getStartingTime() const; 160 161 // get the value of kParamOutputComponents as a OFX::PixelComponentEnum 162 OFX::PixelComponentEnum getOutputComponents() const; 163 164 // sets the value of kParamOutputComponents 165 void setOutputComponents(OFX::PixelComponentEnum comps); 166 167 struct PlaneToRender 168 { 169 float* pixelData; 170 int rowBytes; 171 int numChans; 172 OFX::PixelComponentEnum comps; 173 std::string rawComps; 174 }; 175 176 void convertDepthAndComponents(const void* srcPixelData, 177 const OfxRectI& renderWindow, 178 const OfxRectI& srcBounds, 179 OFX::PixelComponentEnum srcPixelComponents, 180 OFX::BitDepthEnum srcBitDepth, 181 int srcRowBytes, 182 float *dstPixelData, 183 const OfxRectI& dstBounds, 184 OFX::PixelComponentEnum dstPixelComponents, 185 int dstRowBytes); 186 187 private: 188 /** 189 * @brief Called when the input image/video file changed. 190 * 191 * returns true if file exists and parameters successfully guessed, false in case of error. 192 * 193 * This function is only called once: when the filename is first set. 194 * 195 * Besides returning colorspace, premult, components, and componentcount, if it returns true 196 * this function may also set extra format-specific parameters using OFX::Param::setValue. 197 * The parameters must not be animated, since their value must remain the same for a whole sequence. 198 * 199 * You shouldn't do any strong processing as this is called on the main thread and 200 * the getRegionOfDefinition() and decode() should open the file in a separate thread. 201 * 202 * The colorspace may be set if available, else a default colorspace is used. 203 * 204 * You must also return the premultiplication state and pixel components of the image. 205 * When reading an image sequence, this is called only for the first image when the user actually selects the new sequence. 206 **/ 207 virtual bool guessParamsFromFilename(const std::string& newFile, 208 std::string *colorspace, 209 OFX::PreMultiplicationEnum *filePremult, 210 OFX::PixelComponentEnum *components, 211 int *componentCount) = 0; 212 213 /** 214 * @brief Override to clear any cache you may have. 215 **/ clearAnyCache()216 virtual void clearAnyCache() {} 217 218 219 /** 220 * @brief Overload this function to extract the bound of the pixel data 221 * in pixel coordinates and the pixel aspect ratio out of the header 222 * of the image targeted by the filename. 223 **/ 224 virtual bool getFrameBounds(const std::string& filename, 225 OfxTime time, 226 int view, 227 OfxRectI *bounds, 228 OfxRectI *format, 229 double *par, 230 std::string *error, 231 int* tile_width, 232 int* tile_height) = 0; 233 234 /* 235 * In case of plug-ins that can read tiled files, determines whether the image is oriented bottom up or top down. 236 * This is so that the rounding to the tile size is applied correctly. Currently this is only useful for the OIIO plug-in. 237 */ isTileOrientationTopDown()238 virtual bool isTileOrientationTopDown() const { return true; } 239 getFrameRate(const std::string &,double *)240 virtual bool getFrameRate(const std::string& /*filename*/, 241 double* /*fps*/) const { return false; } 242 243 /** 244 * @brief Override this function to actually decode the image contained in the file pointed to by filename. 245 * If the file is a video-stream then you should decode the frame at the time given in parameters. 246 * You must write the decoded image into dstImg. This function should convert the read pixels into the 247 * bitdepth of the dstImg. You can inform the host of the bitdepth you support in the describe() function. 248 * You can always skip the color-space conversion, but for all linear hosts it would produce either 249 * false colors or sub-par performances in the case the end-user has to append a color-space conversion 250 * effect her/himself. 251 **/ 252 virtual void decode(const std::string& filename, OfxTime time, int view, bool isPlayback, const OfxRectI& renderWindow, float *pixelData, const OfxRectI& bounds, OFX::PixelComponentEnum pixelComponents, int pixelComponentCount, int rowBytes); 253 virtual void decodePlane(const std::string& filename, OfxTime time, int view, bool isPlayback, const OfxRectI& renderWindow, float *pixelData, const OfxRectI& bounds, 254 OFX::PixelComponentEnum pixelComponents, int pixelComponentCount, const std::string& rawComponents, int rowBytes); 255 256 257 /** 258 * @brief Override to indicate the time domain. Return false if you know that the 259 * file isn't a video-stream, true when you can find-out the frame range. 260 **/ getSequenceTimeDomain(const std::string &,OfxRangeI &)261 virtual bool getSequenceTimeDomain(const std::string& /*filename*/, 262 OfxRangeI & /*range*/) { return false; } 263 264 /** 265 * @brief Called internally by getTimeDomain(...) 266 **/ 267 bool getSequenceTimeDomainInternal(OfxRangeI& range, bool canSetOriginalFrameRange); 268 269 /** 270 * @brief Used internally by the GenericReader. 271 **/ 272 void timeDomainFromSequenceTimeDomain(const OfxRangeI& sequenceTimeDomain, int startingTime, OfxRangeI* timeDomain); 273 274 /** 275 * @brief Should return true if the file indicated by filename is a video-stream and not 276 * a single image file. 277 **/ 278 virtual bool isVideoStream(const std::string& filename) = 0; 279 enum GetSequenceTimeRetEnum 280 { 281 eGetSequenceTimeWithinSequence = 0, 282 eGetSequenceTimeBeforeSequence, 283 eGetSequenceTimeAfterSequence, 284 eGetSequenceTimeBlack, 285 eGetSequenceTimeError, 286 }; 287 288 289 /** 290 * @brief compute the sequence/file time from time 291 */ 292 GetSequenceTimeRetEnum getSequenceTime(double t, double *sequenceTime) const WARN_UNUSED_RETURN; 293 //GetSequenceTimeRetEnum getSequenceTimeHold(double t, double *sequenceTime) const WARN_UNUSED_RETURN; 294 GetSequenceTimeRetEnum getSequenceTimeBefore(const OfxRangeI& sequenceTimeDomain, BeforeAfterEnum beforeChoice, double *sequenceTime) const; 295 GetSequenceTimeRetEnum getSequenceTimeAfter(const OfxRangeI& sequenceTimeDomain, BeforeAfterEnum afterChoice, double *sequenceTime) const; 296 297 enum GetFilenameRetCodeEnum 298 { 299 eGetFileNameFailed = 0, 300 eGetFileNameReturnedFullRes, 301 eGetFileNameReturnedProxy, 302 eGetFileNameBlack, 303 }; 304 305 /** 306 * @brief Returns the filename of the image at the sequence time t. 307 **/ 308 GetFilenameRetCodeEnum getFilenameAtSequenceTime(double t, 309 bool proxyFiles, 310 bool checkForExistingFile, 311 std::string *filename) const WARN_UNUSED_RETURN; 312 313 314 void copyPixelData(const OfxRectI &renderWindow, 315 const void *srcPixelData, 316 const OfxRectI& srcBounds, 317 OFX::PixelComponentEnum srcPixelComponents, 318 int srcPixelComponentCount, 319 OFX::BitDepthEnum srcPixelDepth, 320 int srcRowBytes, 321 void *dstPixelData, 322 const OfxRectI& dstBounds, 323 OFX::PixelComponentEnum dstPixelComponents, 324 int dstPixelComponentCount, 325 OFX::BitDepthEnum dstBitDepth, 326 int dstRowBytes); 327 328 void scalePixelData(const OfxRectI& originalRenderWindow, 329 const OfxRectI& renderWindow, 330 unsigned int levels, 331 const void* srcPixelData, 332 OFX::PixelComponentEnum srcPixelComponents, 333 int srcPixelComponentCount, 334 OFX::BitDepthEnum srcPixelDepth, 335 const OfxRectI& srcBounds, 336 int srcRowBytes, 337 void* dstPixelData, 338 OFX::PixelComponentEnum dstPixelComponents, 339 int dstPixelComponentCount, 340 OFX::BitDepthEnum dstPixelDepth, 341 const OfxRectI& dstBounds, 342 int dstRowBytes); 343 344 void fillWithBlack(const OfxRectI &renderWindow, 345 void *dstPixelData, 346 const OfxRectI& dstBounds, 347 OFX::PixelComponentEnum dstPixelComponents, 348 int dstPixelComponentCount, 349 OFX::BitDepthEnum dstBitDepth, 350 int dstRowBytes); 351 352 353 void premultPixelData(const OfxRectI &renderWindow, 354 const void *srcPixelData, 355 const OfxRectI& srcBounds, 356 OFX::PixelComponentEnum srcPixelComponents, 357 int srcPixelComponentCount, 358 OFX::BitDepthEnum srcPixelDepth, 359 int srcRowBytes, 360 void *dstPixelData, 361 const OfxRectI& dstBounds, 362 OFX::PixelComponentEnum dstPixelComponents, 363 int dstPixelComponentCount, 364 OFX::BitDepthEnum dstBitDepth, 365 int dstRowBytes); 366 367 void unPremultPixelData(const OfxRectI &renderWindow, 368 const void *srcPixelData, 369 const OfxRectI& srcBounds, 370 OFX::PixelComponentEnum srcPixelComponents, 371 int srcPixelComponentCount, 372 OFX::BitDepthEnum srcPixelDepth, 373 int srcRowBytes, 374 void *dstPixelData, 375 const OfxRectI& dstBounds, 376 OFX::PixelComponentEnum dstPixelComponents, 377 int dstPixelComponentCount, 378 OFX::BitDepthEnum dstBitDepth, 379 int dstRowBytes); 380 381 OfxPointD detectProxyScale(const std::string& originalFileName, const std::string& proxyFileName, OfxTime time); 382 383 void setSequenceFromFile(const std::string& filename); 384 385 void refreshSubLabel(OfxTime time); 386 387 bool checkExtension(const std::string& ext); 388 389 protected: 390 #ifdef OFX_IO_USING_OCIO 391 OFX::BooleanParam* _inputSpaceSet; 392 auto_ptr<GenericOCIO> _ocio; 393 #endif 394 395 OFX::Clip* _syncClip; //< Mantated input clip 396 OFX::Clip * _outputClip; //< Mandated output clip 397 OFX::StringParam *_fileParam; //< The input file 398 399 OFX::IntParam* _firstFrame; //< the first frame in the video file (first frame is 1) or file sequence (>=0) 400 401 OFX::IntParam* _timeOffset; //< the time offset applied to the sequence 402 OFX::IntParam* _startingTime; //< the starting frame of the sequence 403 404 OFX::Int2DParam* _originalFrameRange; //< the original frame range computed the first time by getSequenceTimeDomainInternal 405 406 private: 407 // the following params should not be needed in derived classes. 408 409 OFX::StringParam *_proxyFileParam; //< the proxy input files 410 OFX::Double2DParam *_proxyThreshold; //< the proxy images scale threshold 411 OFX::Double2DParam *_originalProxyScale; //< the original proxy image scale 412 OFX::BooleanParam *_enableCustomScale; //< is custom proxy scale enabled 413 414 OFX::ChoiceParam* _beforeFirst;//< what to do before the first frame 415 OFX::IntParam* _lastFrame; //< the last frame in the sequence (clamped to the time domain) 416 OFX::ChoiceParam* _afterLast; //< what to do after the last frame 417 418 OFX::ChoiceParam* _frameMode;//< do we use a time offset or an absolute starting frame 419 420 OFX::ChoiceParam* _outputComponents; 421 OFX::ChoiceParam* _filePremult; 422 OFX::ChoiceParam* _outputPremult; 423 424 OFX::BooleanParam* _timeDomainUserSet; //< true when the time domain has bee nuser edited 425 426 OFX::BooleanParam* _customFPS; 427 OFX::DoubleParam* _fps; 428 429 OFX::StringParam* _sublabel; 430 OFX::BooleanParam* _guessedParams;//!< was guessParamsFromFilename already successfully called once on this instance 431 432 const std::vector<std::string>& _extensions; 433 434 private: 435 const bool _supportsRGBA; 436 const bool _supportsRGB; 437 const bool _supportsXY; 438 const bool _supportsAlpha; 439 const bool _supportsTiles; 440 const bool _isMultiPlanar; 441 442 OFX::PixelComponentEnum _outputComponentsTable[5]; 443 }; 444 445 446 void GenericReaderDescribe(OFX::ImageEffectDescriptor &desc, 447 const std::vector<std::string>& extensions, // list of supported extensions 448 int evaluation, // plugin quality from 0 (bad) to 100 (perfect) or -1 if not evaluated 449 bool supportsTiles, bool multiPlanar); 450 451 OFX::PageParamDescriptor* GenericReaderDescribeInContextBegin(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context, bool isVideoStreamPlugin, bool supportsRGBA, bool supportsRGB, bool supportsXY, bool supportsAlpha, bool supportsTiles, bool addSeparatorAfterLastParameter); 452 void GenericReaderDescribeInContextEnd(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context, OFX::PageParamDescriptor* page, const char* inputSpaceNameDefault, const char* outputSpaceNameDefault); 453 454 #define mDeclareReaderPluginFactory(CLASS, UNLOADFUNCDEF, ISVIDEOSTREAM) \ 455 class CLASS \ 456 : public OFX::PluginFactoryHelper<CLASS> \ 457 { \ 458 public: \ 459 CLASS(const std::string & id, unsigned int verMaj, unsigned int verMin) \ 460 : OFX::PluginFactoryHelper<CLASS>(id, verMaj, verMin) {} \ 461 virtual void load(); \ 462 virtual void unload() UNLOADFUNCDEF; \ 463 virtual OFX::ImageEffect* createInstance(OfxImageEffectHandle handle, OFX::ContextEnum context); \ 464 bool isVideoStreamPlugin() const { return ISVIDEOSTREAM; } \ 465 virtual void describe(OFX::ImageEffectDescriptor & desc); \ 466 virtual void describeInContext(OFX::ImageEffectDescriptor & desc, OFX::ContextEnum context); \ 467 std::vector<std::string> _extensions; \ 468 }; 469 470 NAMESPACE_OFX_IO_EXIT 471 NAMESPACE_OFX_EXIT 472 473 #endif // ifndef Io_GenericReader_h 474