TuttleOFX  1
ofxsImageEffect.h
Go to the documentation of this file.
00001 #ifndef _ofxsImageEffect_H_
00002 #define _ofxsImageEffect_H_
00003 /*
00004  * OFX Support Library, a library that skins the OFX plug-in API with C++ classes.
00005  * Copyright (C) 2004-2005 The Open Effects Association Ltd
00006  * Author Bruno Nicoletti bruno@thefoundry.co.uk
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *
00011  * Redistributions of source code must retain the above copyright notice,
00012  * this list of conditions and the following disclaimer.
00013  * Redistributions in binary form must reproduce the above copyright notice,
00014  * this list of conditions and the following disclaimer in the documentation
00015  * and/or other materials provided with the distribution.
00016  * Neither the name The Open Effects Association Ltd, nor the names of its
00017  * contributors may be used to endorse or promote products derived from this
00018  * software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00024  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00026  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00027  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *
00031  * The Open Effects Association Ltd
00032  * 1 Wardour St
00033  * London W1D 6PA
00034  * England
00035  *
00036  *
00037  *
00038  */
00039 
00040 /** @file This file contains core code that wraps OFX 'objects' with C++ classes.
00041  *
00042  * This file only holds code that is visible to a plugin implementation, and so hides much
00043  * of the direct OFX objects and any library side only functions.
00044  */
00045 #include "ofxsParam.h"
00046 #include "ofxsInteract.h"
00047 #include "ofxsMessage.h"
00048 #include "ofxParametricParam.h"
00049 #include "extensions/nuke/camera.h"
00050 
00051 #include <ofxProgress.h>
00052 #include <ofxTimeLine.h>
00053 
00054 #include <map>
00055 #include <vector>
00056 #include <string>
00057 #include <algorithm>
00058 #include <sstream>
00059 
00060 /** @brief Nasty macro used to define empty protected copy ctors and assign ops */
00061 #define mDeclareProtectedAssignAndCC( CLASS ) \
00062     CLASS& operator=( const CLASS& ) { assert( false ); return *this; }    \
00063     CLASS( const CLASS & ) { assert( false ); }
00064 
00065 namespace OFX {
00066 namespace Private {
00067 
00068 OfxStatus mainEntryStr( const char*          actionRaw,
00069                         const void*          handleRaw,
00070                         OfxPropertySetHandle inArgsRaw,
00071                         OfxPropertySetHandle outArgsRaw,
00072                         const char*          plugname );
00073 }
00074 }
00075 
00076 /**
00077  * @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries.
00078  */
00079 namespace OFX {
00080 /** forward class declarations */
00081 struct tag_ofxStatus;
00082 
00083 class ClipDescriptor;
00084 class ImageEffectDescriptor;
00085 
00086 class Image;
00087 class Clip;
00088 class ImageEffect;
00089 class ImageMemory;
00090 
00091 /** @brief Enumerates the contexts a plugin can be used in */
00092 enum EContext
00093 {
00094     eContextNone,
00095     eContextGenerator,
00096     eContextFilter,
00097     eContextTransition,
00098     eContextPaint,
00099     eContextGeneral,
00100     eContextRetimer,
00101     eContextReader,
00102     eContextWriter,
00103 };
00104 
00105 const std::string mapContextEnumToString( const EContext s );
00106 
00107 /** @brief Enumerates the pixel depths supported */
00108 enum EBitDepth
00109 {
00110     eBitDepthCustom = -1, ///< some non standard bit depth
00111     eBitDepthNone = 0, ///< bit depth that indicates no data is present
00112     eBitDepthUByte = 1,
00113     eBitDepthUShort = 2,
00114     eBitDepthFloat = 3
00115 };
00116 
00117 const std::string mapBitDepthEnumToString( const EBitDepth e );
00118 
00119 /** @brief Enumerates the component types supported */
00120 enum EPixelComponent
00121 {
00122     ePixelComponentNone,
00123     ePixelComponentRGBA,
00124     ePixelComponentRGB,
00125     ePixelComponentAlpha,
00126     ePixelComponentCustom ///< some non standard pixel type
00127 };
00128 
00129 std::string mapPixelComponentEnumToString( const EPixelComponent e );
00130 
00131 /** @brief Enumerates the ways a fielded image can be extracted from a clip */
00132 enum EFieldExtraction
00133 {
00134     eFieldExtractBoth,   /**< @brief extract both fields */
00135     eFieldExtractSingle, /**< @brief extracts a single field, so you have a half height image */
00136     eFieldExtractDoubled /**< @brief extracts a single field, but doubles up the field, so you have a full height image */
00137 };
00138 
00139 /** @brief Enumerates the kind of render thread safety a plugin has */
00140 enum ERenderSafety
00141 {
00142     eRenderUnsafe,       /**< @brief can only render a single instance at any one time */
00143     eRenderInstanceSafe, /**< @brief can call a single render on an instance, but can render multiple instances simultaneously */
00144     eRenderFullySafe     /**< @brief can call render any number of times on an instance, and render multiple instances simultaneously */
00145 };
00146 
00147 /** @brief Enumerates the fields present in an image */
00148 enum EField
00149 {
00150     eFieldNone,   /**< @brief unfielded image */
00151     eFieldBoth,   /**< @brief fielded image with both fields present */
00152     eFieldLower,  /**< @brief only the spatially lower field is present */
00153     eFieldUpper   /**< @brief only the spatially upper field is present  */
00154 };
00155 
00156 std::string mapFieldEnumToString( const EField e );
00157 
00158 enum EPreMultiplication
00159 {
00160     eImageOpaque,          /**< @brief the image is opaque and so has no premultiplication state */
00161     eImagePreMultiplied,   /**< @brief the image is premultiplied by it's alpha */
00162     eImageUnPreMultiplied, /**< @brief the image is unpremultiplied */
00163 };
00164 
00165 std::string mapPreMultiplicationEnumToString( const EPreMultiplication e );
00166 
00167 
00168 class PluginFactory
00169 {
00170 public:
00171     virtual ~PluginFactory() {}
00172     virtual void                 load()   {}
00173     virtual void                 unload() {}
00174     virtual void                 describe( OFX::ImageEffectDescriptor& desc )                               = 0;
00175     virtual void                 describeInContext( OFX::ImageEffectDescriptor& desc, EContext context ) = 0;
00176     virtual ImageEffect*         createInstance( OfxImageEffectHandle handle, EContext context )         = 0;
00177     virtual const std::string&   getID() const                                                              = 0;
00178     virtual const std::string&   getUID() const                                                             = 0;
00179     virtual unsigned int         getMajorVersion() const                                                    = 0;
00180     virtual unsigned int         getMinorVersion() const                                                    = 0;
00181     virtual OfxPluginEntryPoint* getMainEntry()                                                             = 0;
00182 };
00183 
00184 template<class FACTORY>
00185 class FactoryMainEntryHelper
00186 {
00187 protected:
00188     const std::string& getHelperID() const           { return _id; }
00189     unsigned int       getHelperMajorVersion() const { return _maj; }
00190     unsigned int       getHelperMinorVersion() const { return _min; }
00191 
00192     FactoryMainEntryHelper( const std::string& id, const unsigned int maj, const unsigned int min )
00193     : _id( id )
00194     , _maj( maj )
00195     , _min( min )
00196     {
00197                 std::ostringstream ss;
00198                 ss << id << "." << maj << "." << min;
00199         _uid = ss.str();
00200     }
00201 
00202     const std::string& getHelperUID() const { return _uid; }
00203     static OfxStatus   mainEntry( const char* action, const void* handle, OfxPropertySetHandle in, OfxPropertySetHandle out )
00204     {
00205         return OFX::Private::mainEntryStr( action, handle, in, out, _uid.c_str() );
00206     }
00207 
00208     static std::string _uid;
00209     std::string _id;
00210     unsigned int _maj;
00211     unsigned int _min;
00212 };
00213 
00214 template<class T>
00215 std::string OFX::FactoryMainEntryHelper<T>::_uid;
00216 
00217 template<class FACTORY>
00218 class PluginFactoryHelper : public FactoryMainEntryHelper<FACTORY>,
00219     public PluginFactory
00220 {
00221 public:
00222     PluginFactoryHelper( const std::string& id, unsigned int maj, unsigned int min ) : FactoryMainEntryHelper<FACTORY>( id, maj, min )
00223     {}
00224     virtual ~PluginFactoryHelper() {}
00225     OfxPluginEntryPoint* getMainEntry()          { return FactoryMainEntryHelper<FACTORY>::mainEntry; }
00226     const std::string&   getID() const           { return FactoryMainEntryHelper<FACTORY>::getHelperID(); }
00227     const std::string&   getUID() const          { return FactoryMainEntryHelper<FACTORY>::getHelperUID(); }
00228     unsigned int         getMajorVersion() const { return FactoryMainEntryHelper<FACTORY>::getHelperMajorVersion(); }
00229     unsigned int         getMinorVersion() const { return FactoryMainEntryHelper<FACTORY>::getHelperMinorVersion(); }
00230 };
00231 
00232 #define mDeclarePluginFactory( CLASS, LOADFUNCDEF, UNLOADFUNCDEF ) \
00233     class CLASS : public OFX::PluginFactoryHelper < CLASS > \
00234     { \
00235     public: \
00236         CLASS( const std::string & id, unsigned int verMaj, unsigned int verMin ) : OFX::PluginFactoryHelper < CLASS > ( id, verMaj, verMin ) {} \
00237         virtual ~CLASS() {} \
00238         virtual void load() LOADFUNCDEF ; \
00239         virtual void unload() UNLOADFUNCDEF ; \
00240         virtual void describe( OFX::ImageEffectDescriptor & desc ); \
00241         virtual void describeInContext( OFX::ImageEffectDescriptor & desc, OFX::EContext context ); \
00242         virtual OFX::ImageEffect* createInstance( OfxImageEffectHandle handle, OFX::EContext context ); \
00243     };
00244 
00245 typedef std::vector<PluginFactory*> PluginFactoryArray;
00246 
00247 /** @brief Fetch's a suite from the host and logs errors
00248  *
00249  * All the standard suites are fetched by the support code, you should use this
00250  * to fetch any extra non-standard suites.
00251  */
00252 void* fetchSuite( const char* suiteName, int suiteVersion, bool optional = false );
00253 
00254 ////////////////////////////////////////////////////////////////////////////////
00255 /** @brief A class that lists all the properties of a host */
00256 struct ImageEffectHostDescription
00257 {
00258 public:
00259     std::string hostName;
00260     std::string hostLabel;
00261     bool hostIsBackground;
00262     bool supportsOverlays;
00263     bool supportsMultiResolution;
00264     bool supportsTiles;
00265     bool temporalClipAccess;
00266     bool supportsMultipleClipDepths;
00267     bool supportsMultipleClipPARs;
00268     bool supportsSetableFrameRate;
00269     bool supportsSetableFielding;
00270     bool supportsStringAnimation;
00271     bool supportsCustomInteract;
00272     bool supportsChoiceAnimation;
00273     bool supportsBooleanAnimation;
00274     bool supportsCustomAnimation;
00275     bool supportsParametricParameter;
00276     bool supportsCameraParameter;
00277     int maxParameters;
00278     int maxPages;
00279     int pageRowCount;
00280     int pageColumnCount;
00281     typedef std::vector<EPixelComponent> PixelComponentArray;
00282     PixelComponentArray _supportedComponents;
00283     typedef std::vector<EContext> ContextArray;
00284     ContextArray _supportedContexts;
00285     typedef std::vector<EBitDepth> BitDepthArray;
00286     BitDepthArray _supportedPixelDepths;
00287     bool supportsProgressSuite;
00288     bool supportsTimeLineSuite;
00289 
00290 public:
00291     bool supportsPixelComponent( const OFX::EPixelComponent component ) const
00292     {
00293         return std::find( _supportedComponents.begin(), _supportedComponents.end(), component ) != _supportedComponents.end();
00294     }
00295     bool supportsBitDepth( const OFX::EBitDepth bitDepth ) const
00296     {
00297         return std::find( _supportedPixelDepths.begin(), _supportedPixelDepths.end(), bitDepth ) != _supportedPixelDepths.end();
00298     }
00299     bool supportsContext( const OFX::EContext context ) const
00300     {
00301         return std::find( _supportedContexts.begin(), _supportedContexts.end(), context ) != _supportedContexts.end();
00302     }
00303         
00304     /** @return the pixel depth used by host application, if it doesn't support multiple clip depth. */
00305     EBitDepth getPixelDepth() const
00306     {
00307         if( _supportedPixelDepths.size() == 1 )
00308         {
00309             return _supportedPixelDepths[0];
00310         }
00311         else
00312         {
00313             OFXS_COUT_WARNING("The host doesn't support multiple clip depths, but doesn't define supported pixel depth. (size: " << _supportedPixelDepths.size() << ")" );
00314             return eBitDepthFloat;
00315         }
00316     }
00317 };
00318 
00319 /// retrieve the host description
00320 ImageEffectHostDescription* getImageEffectHostDescription();
00321 
00322 ////////////////////////////////////////////////////////////////////////////////
00323 /** @brief Wraps up a clip */
00324 class ClipDescriptor
00325 {
00326 protected:
00327     mDeclareProtectedAssignAndCC( ClipDescriptor );
00328     ClipDescriptor( void ) { assert( false ); }
00329 
00330 protected:
00331     /** @brief name of the clip */
00332     std::string _clipName;
00333 
00334     /** @brief properties for this clip */
00335     PropertySet _clipProps;
00336 
00337 protected:
00338     /** @brief hidden constructor */
00339     ClipDescriptor( const std::string& name, OfxPropertySetHandle props );
00340 
00341     friend class ImageEffectDescriptor;
00342 
00343 public:
00344     const PropertySet& getPropertySet() const { return _clipProps; }
00345 
00346     PropertySet& getPropertySet() { return _clipProps; }
00347 
00348     /** @brief set the label properties */
00349     void setLabels( const std::string& label, const std::string& shortLabel, const std::string& longLabel );
00350     void setLabel( const std::string& label ) { setLabels( label, label, label ); }
00351 
00352     /** @brief set how fielded images are extracted from the clip defaults to eFieldExtractDoubled */
00353     void setFieldExtraction( EFieldExtraction v );
00354 
00355     /** @brief set which components are supported, defaults to none set, this must be called at least once! */
00356     void addSupportedComponent( EPixelComponent v );
00357 
00358     /** @brief set which components are supported. This version adds by the raw C-string label, allowing you to add
00359      * custom component types */
00360     void addSupportedComponent( const std::string& comp );
00361 
00362     /** @brief say whether we are going to do random temporal access on this clip, defaults to false */
00363     void setTemporalClipAccess( bool v );
00364 
00365     /** @brief say whether if the clip is optional, defaults to false */
00366     void setOptional( bool v );
00367 
00368     /** @brief say whether this clip supports tiling, defaults to true */
00369     void setSupportsTiles( bool v );
00370 
00371     /** @brief say whether this clip is a 'mask', so the host can know to replace with a roto or similar, defaults to false */
00372     void setIsMask( bool v );
00373 };
00374 
00375 ////////////////////////////////////////////////////////////////////////////////
00376 /** @brief Wraps up an effect descriptor, used in the describe actions */
00377 class ImageEffectDescriptor : public ParamSetDescriptor
00378 {
00379 protected:
00380     mDeclareProtectedAssignAndCC( ImageEffectDescriptor );
00381     ImageEffectDescriptor( void ) { assert( false ); }
00382 
00383 protected:
00384     /** @brief The effect handle */
00385     OfxImageEffectHandle _effectHandle;
00386 
00387     /** @brief properties for this clip */
00388     PropertySet _effectProps;
00389 
00390     /** @brief Set of all previously defined parameters, defined on demand */
00391     std::map<std::string, ClipDescriptor*> _definedClips;
00392 
00393     /** @brief Set of strings for clip preferences action (stored in here so the array persists and can be used in a property name)*/
00394     std::map<std::string, std::string> _clipComponentsPropNames;
00395     std::map<std::string, std::string> _clipDepthPropNames;
00396     std::map<std::string, std::string> _clipPARPropNames;
00397     std::map<std::string, std::string> _clipROIPropNames;
00398     std::map<std::string, std::string> _clipFrameRangePropNames;
00399 
00400     std::auto_ptr<EffectInteractWrap> _overlayDescriptor;
00401 
00402 public:
00403     /** @brief ctor */
00404     ImageEffectDescriptor( OfxImageEffectHandle handle );
00405 
00406     /** @brief dtor */
00407     ~ImageEffectDescriptor();
00408 
00409     const PropertySet& getPropertySet() const { return _effectProps; }
00410 
00411     PropertySet& getPropertySet() { return _effectProps; }
00412 
00413     OfxImageEffectHandle getImageEffectHandle() { return _effectHandle; }
00414 
00415     /** @brief, set the label properties in a plugin */
00416     void setLabels( const std::string& label, const std::string& shortLabel, const std::string& longLabel );
00417     void setLabel( const std::string& label ) { setLabels(label, label, label); }
00418 
00419     void setDescription( const std::string& description );
00420 
00421     /** @brief Set the plugin grouping, defaults to "" */
00422     void setPluginGrouping( const std::string& group );
00423 
00424     /** @brief Add a context to those supported, defaults to none, must be called at least once */
00425     void addSupportedContext( EContext v );
00426 
00427     /** @brief Add a pixel depth to those supported, defaults to none, must be called at least once */
00428     void addSupportedBitDepth( EBitDepth v );
00429 
00430     /** @brief Add a file extension to those supported, defaults to none */
00431     void addSupportedExtension( const std::string& extension );
00432     void addSupportedExtensions( const std::vector<std::string>& extensions );
00433 
00434     /** @brief Is the plugin single instance only ? defaults to false */
00435     void setSingleInstance( bool v );
00436 
00437     /** @brief Does the plugin expect the host to perform per frame SMP threading defaults to true */
00438     void setHostFrameThreading( bool v );
00439 
00440     /** @brief Does the plugin support multi resolution images, defaults to true */
00441     void setSupportsMultiResolution( bool v );
00442 
00443     /** @brief Does the plugin support image tiling, defaults to true */
00444     void setSupportsTiles( bool v );
00445 
00446     /** @brief Does the plugin perform temporal clip access, defaults to false */
00447     void setTemporalClipAccess( bool v );
00448 
00449     /** @brief Does the plugin want to have render called twice per frame in all circumanstances for fielded images ? defaults to true */
00450     void setRenderTwiceAlways( bool v );
00451 
00452     /** @brief Does the plugin support inputs and output clips of differing depths, defaults to false */
00453     void setSupportsMultipleClipDepths( bool v );
00454 
00455     /** @brief Does the plugin support inputs and output clips of pixel aspect ratios, defaults to false */
00456     void setSupportsMultipleClipPARs( bool v );
00457 
00458     /** @brief How thread safe is the plugin, defaults to eRenderInstanceSafe */
00459     void setRenderThreadSafety( ERenderSafety v );
00460 
00461     /** @brief If the slave  param changes the clip preferences need to be re-evaluated */
00462     void addClipPreferencesSlaveParam( ParamDescriptor& p );
00463 
00464     /** @brief Create a clip, only callable from describe in context
00465      *
00466      * The returned clip \em must not be deleted by the client code. This is all managed by the ImageEffectDescriptor itself.
00467      */
00468     ClipDescriptor* defineClip( const std::string& name );
00469 
00470     /** @brief Access to the string maps needed for runtime properties. Because the char array must persist after the call,
00471      * we need these to be stored in the descriptor, which is only deleted on unload.*/
00472 
00473     const std::map<std::string, std::string>& getClipComponentPropNames() const  { return _clipComponentsPropNames; }
00474     const std::map<std::string, std::string>& getClipDepthPropNames() const      { return _clipDepthPropNames; }
00475     const std::map<std::string, std::string>& getClipPARPropNames() const        { return _clipPARPropNames; }
00476     const std::map<std::string, std::string>& getClipROIPropNames() const        { return _clipROIPropNames; }
00477     const std::map<std::string, std::string>& getClipFrameRangePropNames() const { return _clipFrameRangePropNames; }
00478 
00479     /** @brief override this to create an interact for the effect */
00480     virtual void setOverlayInteractDescriptor(EffectInteractWrap* desc);
00481 };
00482 
00483 ////////////////////////////////////////////////////////////////////////////////
00484 /** @brief Wraps up an image */
00485 class Image
00486 {
00487 protected:
00488     /** @brief the handle that holds this image */
00489     PropertySet _imageProps;
00490 
00491     /** @brief friend so we get access to ctor */
00492     friend class Clip;
00493 
00494     void* _pixelData;                   /**< @brief the base address of the image */
00495     EPixelComponent _pixelComponents;     /**< @brief get the components in the image */
00496     int _rowDistanceBytes;                    /**< @brief the number of bytes per scanline */
00497 
00498     int _pixelBytes;                  /**< @brief the number of bytes per pixel */
00499     EBitDepth _pixelDepth;                 /**< @brief get the pixel depth */
00500     EPreMultiplication _preMultiplication; /**< @brief premultiplication on the image */
00501     OfxRectI _regionOfDefinition;          /**< @brief the RoD in pixel coordinates, this may be more or less than the bounds! */
00502     OfxRectI _bounds;                      /**< @brief the bounds on the pixel data */
00503     double _pixelAspectRatio;            /**< @brief the pixel aspect ratio */
00504     EField _field;                        /**< @brief which field this represents */
00505     std::string _uniqueID;                   /**< @brief the unique ID of this image */
00506     OfxPointD _renderScale;                  /**< @brief any scaling factor applied to the image */
00507 
00508 public:
00509     /** @brief ctor */
00510     Image( OfxPropertySetHandle props );
00511 
00512     /** @brief dtor */
00513     virtual ~Image();
00514 
00515     const PropertySet& getPropertySet() const { return _imageProps; }
00516 
00517     PropertySet& getPropertySet() { return _imageProps; }
00518 
00519     /** @brief get the pixel depth */
00520     EBitDepth getPixelDepth() const { return _pixelDepth; }
00521 
00522     /** @brief get the components in the image */
00523     EPixelComponent getPixelComponents() const { return _pixelComponents; }
00524 
00525     /** @brief get the string representing the pixel components */
00526     std::string getPixelComponentsProperty() const { return _imageProps.propGetString( kOfxImageEffectPropComponents ); }
00527 
00528     /** @brief premultiplication on the image */
00529     EPreMultiplication getPreMultiplication() const { return _preMultiplication; }
00530 
00531     /** @brief get the scale factor that has been applied to this image */
00532     OfxPointD getRenderScale() const { return _renderScale; }
00533 
00534     /** @brief get the scale factor that has been applied to this image */
00535     double getPixelAspectRatio() const { return _pixelAspectRatio; }
00536 
00537     /** @brief get the pixel data for this image */
00538     void* getPixelData() const { return _pixelData; }
00539 
00540     /** @brief get the region of definition (in pixel coordinates) of this image */
00541     OfxRectI getRegionOfDefinition() const { return _regionOfDefinition; }
00542 
00543     /** @brief get the bounds on the image data (in pixel coordinates) of this image */
00544     OfxRectI getBounds() const { return _bounds; }
00545         
00546     OfxPointI getBoundsSize() const { const OfxPointI res = { _bounds.x2 - _bounds.x1, _bounds.y2 - _bounds.y1 }; return res; }
00547 
00548         std::size_t getPixelBytes() const;
00549         
00550     /** @brief get the distance between 2 rows in bytes, may be negative */
00551     int getRowDistanceBytes() const { return _rowDistanceBytes; }
00552         
00553     /** @brief get the data row size in bytes, by definition >= 0 */
00554     std::size_t getBoundsRowDataBytes() const;
00555         
00556         std::size_t getBoundsNbPixels() const;
00557         
00558     std::size_t getBoundsImageDataBytes() const;
00559         
00560     bool isLinearBuffer() const { return (int)(getBoundsRowDataBytes()) == getRowDistanceBytes(); }
00561 
00562     /** @brief get the fielding of this image */
00563     EField getField() const { return _field; }
00564 
00565     /** @brief the unique ID of this image */
00566     std::string getUniqueIdentifier() const { return _uniqueID; }
00567 
00568     /** @brief return a pixel pointer
00569      *
00570      * x and y are in pixel coordinates
00571      *
00572      * If the components are custom, then this will return NULL as the support code
00573      * can't know the pixel size to do the work.
00574      */
00575     void* getPixelAddress( int x, int y );
00576 };
00577 
00578 ////////////////////////////////////////////////////////////////////////////////
00579 /** @brief Wraps up a clip instance */
00580 class Clip
00581 {
00582 protected:
00583     mDeclareProtectedAssignAndCC( Clip );
00584 
00585     /** @brief name of the clip */
00586     std::string _clipName;
00587 
00588     /** @brief properties for this clip */
00589     PropertySet _clipProps;
00590 
00591     /** @brief handle for this clip */
00592     OfxImageClipHandle _clipHandle;
00593 
00594     /** @brief effect instance that owns this clip */
00595     ImageEffect* _effect;
00596 
00597     /** @brief hidden constructor */
00598     Clip( ImageEffect* effect, const std::string& name, OfxImageClipHandle handle, OfxPropertySetHandle props );
00599 
00600     /** @brief so one can be made */
00601     friend class ImageEffect;
00602 
00603 public:
00604     /// get the underlying property set on this clip
00605     const PropertySet& getPropertySet() const { return _clipProps; }
00606 
00607     /// get the underlying property set on this clip
00608     PropertySet& getPropertySet() { return _clipProps; }
00609 
00610     /// get the OFX clip handle
00611     OfxImageClipHandle getHandle() { return _clipHandle; }
00612 
00613     /** @brief get the name */
00614     const std::string& name( void ) const { return _clipName; }
00615 
00616     /** @brief fetch the labels */
00617     void getLabels( std::string& label, std::string& shortLabel, std::string& longLabel ) const;
00618 
00619     /** @brief what is the pixel depth images will be given to us as */
00620     EBitDepth getPixelDepth( void ) const;
00621 
00622     /** @brief what is the components images will be given to us as */
00623     EPixelComponent getPixelComponents( void ) const;
00624 
00625     /** @brief get the string representing the pixel components */
00626     std::string getPixelComponentsProperty( void ) const { return _clipProps.propGetString( kOfxImageEffectPropComponents ); }
00627 
00628     /** @brief what is the actual pixel depth of the clip */
00629     EBitDepth getUnmappedPixelDepth( void ) const;
00630 
00631     /** @brief what is the component type of the clip */
00632     EPixelComponent getUnmappedPixelComponents( void ) const;
00633 
00634     /** @brief get the string representing the pixel components */
00635     std::string getUnmappedPixelComponentsProperty( void ) const { return _clipProps.propGetString( kOfxImageClipPropUnmappedComponents ); }
00636 
00637     /** @brief get the components in the image */
00638     EPreMultiplication getPreMultiplication( void ) const;
00639 
00640     /** @brief which spatial field comes first temporally */
00641     EField getFieldOrder( void ) const;
00642 
00643     /** @brief is the clip connected */
00644     bool isConnected( void ) const;
00645 
00646     /** @brief can the clip be continuously sampled */
00647     bool hasContinuousSamples( void ) const;
00648 
00649     /** @brief get the scale factor that has been applied to this clip */
00650     double getPixelAspectRatio( void ) const;
00651 
00652     /** @brief get the frame rate, in frames per second on this clip, after any clip preferences have been applied */
00653     double getFrameRate( void ) const;
00654 
00655     /** @brief return the range of frames over which this clip has images, after any clip preferences have been applied */
00656     OfxRangeD getFrameRange( void ) const;
00657 
00658     /** @brief get the frame rate, in frames per second on this clip, before any clip preferences have been applied */
00659     double getUnmappedFrameRate( void ) const;
00660 
00661     /** @brief return the range of frames over which this clip has images, before any clip preferences have been applied */
00662     OfxRangeD getUnmappedFrameRange( void ) const;
00663 
00664     /** @brief get the RoD for this clip in the cannonical coordinate system */
00665     OfxRectD getCanonicalRod( const OfxTime t ) const;
00666     OfxRectD getCanonicalRod( const OfxTime t, const OfxPointD& renderScale ) const;
00667     OfxPointD getCanonicalRodSize( const OfxTime t ) const
00668     {
00669         OfxRectD r = getCanonicalRod(t);
00670         OfxPointD p = {r.x2-r.x1, r.y2-r.y1};
00671         return p;
00672     }
00673     OfxPointD getCanonicalRodSize( const OfxTime t, const OfxPointD& renderScale ) const
00674     {
00675         OfxPointD p = getCanonicalRodSize(t);
00676         p.x *= renderScale.x;
00677         p.y *= renderScale.y;
00678         return p;
00679     }
00680 
00681     /** @brief get the RoD for this clip in pixel space */
00682     OfxRectI getPixelRod( const OfxTime t ) const;
00683     OfxRectI getPixelRod( const OfxTime t, const OfxPointD& renderScale ) const;
00684     OfxPointI getPixelRodSize( const OfxTime t ) const
00685     {
00686         OfxRectI r = getPixelRod(t);
00687         OfxPointI p = {r.x2-r.x1, r.y2-r.y1};
00688         return p;
00689     }
00690     OfxPointI getPixelRodSize( const OfxTime t, const OfxPointD& renderScale ) const
00691     {
00692         OfxPointI p = getPixelRodSize(t);
00693         p.x = static_cast<int>( p.x * renderScale.x );
00694         p.y = static_cast<int>( p.y * renderScale.y );
00695         return p;
00696     }
00697 
00698     /** @brief fetch an image
00699      *
00700      * When finished with, the client code must delete the image.
00701      *
00702      * If the same image is fetched twice, it must be deleted in each case, they will not be the same pointer.
00703      */
00704     Image* fetchImage( OfxTime t );
00705 
00706     /** @brief fetch an image, with a specific region in cannonical coordinates
00707      *
00708      * When finished with, the client code must delete the image.
00709      *
00710      * If the same image is fetched twice, it must be deleted in each case, they will not be the same pointer.
00711      */
00712     Image* fetchImage( OfxTime t, OfxRectD bounds );
00713 
00714     /** @brief fetch an image, with a specific region in cannonical coordinates
00715      *
00716      * When finished with, the client code must delete the image.
00717      *
00718      * If the same image is fetched twice, it must be deleted in each case, they will not be the same pointer.
00719      */
00720     Image* fetchImage( OfxTime t, OfxRectD* bounds )
00721     {
00722         if( bounds )
00723             return fetchImage( t, *bounds );
00724         else
00725             return fetchImage( t );
00726     }
00727 
00728 };
00729 
00730 ////////////////////////////////////////////////////////////////////////////////
00731 /** @brief Class that skins image memory allocation */
00732 class ImageMemory
00733 {
00734 protected:
00735     OfxImageMemoryHandle _handle;
00736         bool _alloc;
00737         
00738 public:
00739     ImageMemory();
00740     ImageMemory( size_t nBytes, ImageEffect* associatedEffect = 0 );
00741     ~ImageMemory();
00742 
00743         void alloc( size_t nBytes, ImageEffect* associatedEffect );
00744         
00745     /** @brief lock the memory and return a pointer to it */
00746     void* lock( void );
00747 
00748     /** @brief unlock the memory */
00749     void unlock( void );
00750 };
00751 
00752 ////////////////////////////////////////////////////////////////////////////////
00753 /** @brief POD struct to pass rendering arguments into @ref ImageEffect::render and @ref OFX::ImageEffect::isIdentity */
00754 struct RenderArguments
00755 {
00756     double time;
00757     OfxPointD renderScale;
00758     OfxRectI renderWindow;
00759     EField fieldToRender;
00760 };
00761 
00762 /** @brief POD struct to pass arguments into  @ref OFX::ImageEffect::render */
00763 struct BeginSequenceRenderArguments
00764 {
00765     OfxRangeD frameRange;
00766     double frameStep;
00767     bool isInteractive;
00768     OfxPointD renderScale;
00769 };
00770 
00771 /** @brief POD struct to pass arguments into  @ref OFX::ImageEffect::beginSequenceRender */
00772 struct EndSequenceRenderArguments
00773 {
00774     bool isInteractive;
00775     OfxPointD renderScale;
00776 };
00777 
00778 /** @brief POD struct to pass arguments into  @ref OFX::ImageEffect::getRegionOfDefinition */
00779 struct RegionOfDefinitionArguments
00780 {
00781     double time;
00782     OfxPointD renderScale;
00783 };
00784 
00785 /** @brief POD struct to pass arguments into @ref OFX::ImageEffect::getRegionsOfInterest */
00786 struct RegionsOfInterestArguments
00787 {
00788     double time;
00789     OfxPointD renderScale;
00790     OfxRectD regionOfInterest;
00791 };
00792 
00793 /** @brief Class used to set regions of interest on a clip in @ref OFX::ImageEffect::getRegionsOfInterest
00794  *
00795  * This is a base class, the actual class is private and you don't need to see the glue involved.
00796  */
00797 class RegionOfInterestSetter
00798 {
00799 public:
00800     /** @brief function to set the RoI of a clip, pass in the clip to set the RoI of, and the RoI itself */
00801     virtual void setRegionOfInterest( const Clip& clip, const OfxRectD& RoI ) = 0;
00802     virtual ~RegionOfInterestSetter() = 0;
00803 };
00804 
00805 /** @brief POD struct to pass arguments into @ref OFX::ImageEffect::getFramesNeeded */
00806 struct FramesNeededArguments
00807 {
00808     double time;
00809 };
00810 
00811 /** @brief Class used to set the frames needed to render a single frame of a clip in @ref OFX::ImageEffect::getFramesNeeded
00812  *
00813  * This is a base class, the actual class is private and you don't need to see the glue involved.
00814  */
00815 class FramesNeededSetter
00816 {
00817 public:
00818     /** @brief function to set the frames needed on a clip, the range is min <= time <= max */
00819     virtual void setFramesNeeded( const Clip& clip, const OfxRangeD& range ) = 0;
00820     virtual ~FramesNeededSetter() = 0;
00821 };
00822 
00823 /** @brief Class used to set the clip preferences of the effect.
00824  */
00825 class ClipPreferencesSetter
00826 {
00827 OFX::PropertySet outArgs_;
00828 bool doneSomething_;
00829 typedef std::map<std::string, std::string> StringStringMap;
00830 const StringStringMap& clipDepthPropNames_;
00831 const StringStringMap& clipComponentPropNames_;
00832 const StringStringMap& clipPARPropNames_;
00833 const std::string& extractValueForName( const StringStringMap& m, const std::string& name );
00834 
00835 public:
00836     ImageEffectHostDescription* _imageEffectHostDescription;
00837 
00838 public:
00839     ClipPreferencesSetter( OFX::PropertySet       props,
00840                            const StringStringMap& depthPropNames,
00841                            const StringStringMap& componentPropNames,
00842                            const StringStringMap& PARPropNames )
00843         : outArgs_( props ),
00844         doneSomething_( false ),
00845         clipDepthPropNames_( depthPropNames ),
00846         clipComponentPropNames_( componentPropNames ),
00847         clipPARPropNames_( PARPropNames )
00848     {
00849             _imageEffectHostDescription = getImageEffectHostDescription();
00850     }
00851 
00852     bool didSomething( void ) const { return doneSomething_; }
00853 
00854     /** @brief, force the host to set a clip's mapped component type to be \em comps.
00855      *
00856      * Only callable on non optional clips in all contexts. Must set comps to be one of the types the effect says it supports on the given clip.
00857      *
00858      * See the OFX API documentation for the default values of this.
00859      */
00860     void setClipComponents( Clip& clip, EPixelComponent comps );
00861 
00862     /** @brief, force the host to set a clip's mapped bit depth be \em bitDepth
00863      *
00864      * Only callable if the OFX::ImageEffectHostDescription::supportsMultipleClipDepths is true.
00865      *
00866      * See the OFX API documentation for the default values of this.
00867      */
00868     void setClipBitDepth( Clip& clip, EBitDepth bitDepth );
00869 
00870     /** @brief, force the host to set a clip's mapped Pixel Aspect Ratio to be \em PAR
00871      *
00872      * Only callable if the OFX::ImageEffectHostDescription::supportsMultipleClipPARs is true.
00873      *
00874      * Default is up to the host, generally based on the input clips.
00875      *
00876      * Not supported by most host applications.
00877      */
00878     void setPixelAspectRatio( Clip& clip, double PAR );
00879 
00880     /** @brief Allows an effect to change the output frame rate
00881      *
00882      * Only callable if OFX::ImageEffectHostDescription::supportsSetableFrameRate is true.
00883      *
00884      * Default is controlled by the host, typically the framerate of the input clips.
00885      */
00886     void setOutputFrameRate( double v );
00887 
00888     /** @brief Set the premultiplication state of the output clip.
00889      *
00890      * Defaults to the premultiplication state of ???
00891      */
00892     void setOutputPremultiplication( EPreMultiplication v );
00893 
00894     /** @brief Set whether the effect can be continously sampled.
00895      *
00896      * Defaults to false.
00897      */
00898     void setOutputHasContinousSamples( bool v );
00899 
00900     /** @brief Sets whether the effect will produce different images in all frames, even if the no params or input images are varying (eg: a noise generator).
00901      *
00902      * Defaults to false.
00903      */
00904     void setOutputFrameVarying( bool v );
00905 
00906     /** @brief Sets the output fielding
00907      *
00908      * Default is host dependent, must be one of
00909      * - eFieldNone,
00910      * - eFieldLower,
00911      * - eFieldUpper
00912      */
00913     void setOutputFielding( EField v );
00914 };
00915 
00916 static const OfxPointD kNoRenderScale = { 1.0, 1.0 };
00917 
00918 /** @brief POD data structure passing in the instance changed args */
00919 struct InstanceChangedArgs
00920 {
00921     InstanceChangedArgs( const OfxTime time = 0.0, const OfxPointD renderScale = kNoRenderScale, const InstanceChangeReason reason = OFX::eChangePluginEdit )
00922     : time(time)
00923     , renderScale( renderScale )
00924     , reason( reason )
00925     {}
00926 
00927     OfxTime time; //< time of the change
00928     OfxPointD renderScale; ///< the renderscale on the instance
00929     InstanceChangeReason reason; ///< why did it change
00930 };
00931 
00932 
00933 ////////////////////////////////////////////////////////////////////////////////
00934 /** @brief Wraps up an effect instance, plugin implementations need to inherit from this */
00935 class ImageEffect : public ParamSet
00936 {
00937 protected:
00938     mDeclareProtectedAssignAndCC( ImageEffect );
00939 
00940 private:
00941     /** @brief to get access to the effect handle without exposing it generally via a function */
00942     friend class ImageMemory;
00943 
00944     /** @brief The effect handle */
00945     OfxImageEffectHandle _effectHandle;
00946 
00947     /** @brief properties for this clip */
00948     PropertySet _effectProps;
00949 
00950     /** @brief the context of the effect */
00951     EContext _context;
00952 
00953     /** @brief Set of all previously defined parameters, defined on demand */
00954     std::map<std::string, Clip*> _fetchedClips;
00955 
00956     /** @brief the overlay interacts that are open on this image effect */
00957     std::list<OverlayInteract*> _overlayInteracts;
00958 
00959     /** @brief cached result of whether progress start succeeded. */
00960     bool _progressStartSuccess;
00961 
00962 public:
00963     /** @brief ctor */
00964     ImageEffect( OfxImageEffectHandle handle );
00965 
00966     /** @brief dtor */
00967     virtual ~ImageEffect();
00968 
00969     const PropertySet& getPropertySet() const { return _effectProps; }
00970 
00971     PropertySet& getPropertySet() { return _effectProps; }
00972 
00973     OfxImageEffectHandle getHandle( void ) const { return _effectHandle; }
00974 
00975     /** @brief the context this effect was instantiate in */
00976     EContext getContext( void ) const;
00977 
00978     /** @brief size of the project */
00979     OfxPointD getProjectSize( void ) const;
00980 
00981     /** @brief origin of the project */
00982     OfxPointD getProjectOffset( void ) const;
00983 
00984     /** @brief extent of the project */
00985     OfxPointD getProjectExtent( void ) const;
00986 
00987     /** @brief pixel aspect ratio of the project */
00988     double getProjectPixelAspectRatio( void ) const;
00989 
00990     /** @brief how long does the effect last */
00991     double getEffectDuration( void ) const;
00992 
00993     /** @brief the frame rate of the project */
00994     double getFrameRate( void ) const;
00995 
00996     /** @brief is the instance currently being interacted with */
00997     bool isInteractive( void ) const;
00998 
00999     /** @brief set the instance to be sequentially renderred, this should have been part of clip preferences! */
01000     void setSequentialRender( bool v );
01001 
01002     /** @brief Have we informed the host we want to be seqentially renderred ? */
01003     bool getSequentialRender( void ) const;
01004 
01005     OFX::Message::EMessageReply sendMessage( OFX::Message::EMessageType type, const std::string& id, const std::string& msg );
01006 
01007     /** @brief Fetch the named clip from this instance
01008      *
01009      * The returned clip \em must not be deleted by the client code. This is all managed by the ImageEffect itself.
01010      */
01011     Clip* fetchClip( const std::string& name );
01012 
01013     CameraParam* fetchCameraParam( const std::string& name );
01014 
01015     /** @brief does the host want us to abort rendering? */
01016     bool abort() const;
01017 
01018     /** @brief adds a new interact to the set of interacts open on this effect */
01019     void addOverlayInteract( OverlayInteract* interact );
01020 
01021     /** @brief removes an interact to the set of interacts open on this effect */
01022     void removeOverlayInteract( OverlayInteract* interact );
01023 
01024     /** @brief force all overlays on this interact to be redrawn */
01025     void redrawOverlays( void );
01026 
01027     ////////////////////////////////////////////////////////////////////////////////
01028     // these are actions that need to be overridden by a plugin that implements an effect host
01029 
01030     /** @brief The purge caches action, a request for an instance to free up as much memory as possible in low memory situations */
01031     virtual void purgeCaches( void );
01032 
01033     /** @brief The sync private data action, called when the effect needs to sync any private data to persistant parameters */
01034     virtual void syncPrivateData( void );
01035 
01036     /** @brief client render function, this is one of the few that must be overridden */
01037     virtual void render( const RenderArguments& args ) = 0;
01038 
01039     /** @brief client begin sequence render function */
01040     virtual void beginSequenceRender( const BeginSequenceRenderArguments& args );
01041 
01042     /** @brief client end sequence render function */
01043     virtual void endSequenceRender( const EndSequenceRenderArguments& args );
01044 
01045     /** @brief client is identity function, returns the clip and time for the identity function
01046      *
01047      * If the effect would do no processing for the given param set and render arguments, then this
01048      * function should return true and set the \em identityClip pointer to point to the clip that is the identity
01049      * and \em identityTime to be the time at which to access the clip for the identity operation.
01050      */
01051     virtual bool isIdentity( const RenderArguments& args, Clip*& identityClip, double& identityTime );
01052 
01053     /** @brief The get RoD action.
01054      *
01055      * If the effect wants change the rod from the default value (which is the union of RoD's of all input clips)
01056      * it should set the \em rod argument and return true.
01057      *
01058      * This is all in cannonical coordinates.
01059      */
01060     virtual bool getRegionOfDefinition( const RegionOfDefinitionArguments& args, OfxRectD& rod );
01061 
01062     /** @brief the get region of interest action
01063      *
01064      * If the effect wants change its region of interest on any input clip from the default values (which is the same as the RoI in the arguments)
01065      * it should do so by calling the OFX::RegionOfInterestSetter::setRegionOfInterest function on the \em rois argument.
01066      *
01067      * Note, everything is in \em cannonical \em coordinates.
01068      */
01069     virtual void getRegionsOfInterest( const RegionsOfInterestArguments& args, RegionOfInterestSetter& rois );
01070 
01071     /** @brief the get frames needed action
01072      *
01073      * If the effect wants change the frames needed on an input clip from the default values (which is the same as the frame to be renderred)
01074      * it should do so by calling the OFX::FramesNeededSetter::setFramesNeeded function on the \em frames argument.
01075      */
01076     virtual void getFramesNeeded( const FramesNeededArguments& args, FramesNeededSetter& frames );
01077 
01078     /** @brief get the clip preferences */
01079     virtual void getClipPreferences( ClipPreferencesSetter& clipPreferences );
01080 
01081     /** @brief the effect is about to be actively edited by a user, called when the first user interface is opened on an instance */
01082     virtual void beginEdit( void );
01083 
01084     /** @brief the effect is no longer being edited by a user, called when the last user interface is closed on an instance */
01085     virtual void endEdit( void );
01086 
01087     /** @brief the effect is about to have some values changed */
01088     virtual void beginChanged( InstanceChangeReason reason );
01089 
01090     /** @brief called when a param has just had its value changed */
01091     virtual void changedParam( const InstanceChangedArgs& args, const std::string& paramName );
01092 
01093     /** @brief called when a clip has just been changed in some way (a rewire maybe) */
01094     virtual void changedClip( const InstanceChangedArgs& args, const std::string& clipName );
01095 
01096     /** @brief the effect has just had some values changed */
01097     virtual void endChanged( InstanceChangeReason reason );
01098 
01099     /** @brief what is the time domain of this effect, valid only in the general context
01100      *
01101      * return true if range was set, otherwise the default (the union of the time domain of all input clips) is used
01102      */
01103     virtual bool getTimeDomain( OfxRangeD& range );
01104 
01105     /// Start doing progress.
01106     void progressStart( const std::string& message );
01107 
01108     /// finish yer progress
01109     void progressEnd();
01110 
01111     /// set the progress to some level of completion,
01112     /// returns true if you should abandon processing, false to continue
01113     bool progressUpdate( const double t );
01114 
01115     /// get the current time on the timeline. This is not necessarily the same
01116     /// time as being passed to an action (eg render)
01117     double timeLineGetTime();
01118 
01119     /// set the timeline to a specific time
01120     void timeLineGotoTime( const double t );
01121 
01122     /// get the first and last times available on the effect's timeline
01123     void timeLineGetBounds( double& t1, double& t2 );
01124     inline OfxRangeD timeLineGetBounds() { OfxRangeD range; timeLineGetBounds( range.min, range.max ); return range; }
01125 };
01126 
01127 ////////////////////////////////////////////////////////////////////////////////
01128 /** @brief The OFX::Plugin namespace. All the functions in here needs to be defined by each plugin that uses the support libs.
01129  */
01130 namespace Plugin {
01131 /** @brief Plugin side function used to identify the plugin to the support library */
01132 void getPluginID( OFX::PluginFactoryArray& id );
01133 
01134 /// If the client has defined its own exception type, allow it to catch it in the main function
01135 #ifdef OFX_CLIENT_EXCEPTION_TYPE
01136 OfxStatus catchException( OFX_CLIENT_EXCEPTION_TYPE& ex );
01137 #endif
01138 };
01139 
01140 };
01141 
01142 // undeclare the protected assign and CC macro
01143 #undef mDeclareProtectedAssignAndCC
01144 
01145 #endif