TuttleOFX  1
ofxsImageEffect.cpp
Go to the documentation of this file.
00001 /*
00002 * OFX Support Library, a library that skins the OFX plug-in API with C++ classes.
00003 * Copyright (C) 2004-2007 The Open Effects Association Ltd
00004 * Author Bruno Nicoletti bruno@thefoundry.co.uk
00005 *
00006 * Redistribution and use in source and binary forms, with or without
00007 * modification, are permitted provided that the following conditions are met:
00008 *
00009 * Redistributions of source code must retain the above copyright notice,
00010 * this list of conditions and the following disclaimer.
00011 * Redistributions in binary form must reproduce the above copyright notice,
00012 * this list of conditions and the following disclaimer in the documentation
00013 * and/or other materials provided with the distribution.
00014 * Neither the name The Open Effects Association Ltd, nor the names of its
00015 * contributors may be used to endorse or promote products derived from this
00016 * software without specific prior written permission.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00019 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00020 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00021 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00022 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00024 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00025 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00027 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028 *
00029 * The Open Effects Association Ltd
00030 * 1 Wardour St
00031 * London W1D 6PA
00032 * England
00033 *
00034 *
00035 */
00036 
00037 /** @brief This file contains code that skins the ofx effect suite */
00038 
00039 #include "ofxsSupportPrivate.h"
00040 #include "ofxsUtilities.h"
00041 
00042 #include <tuttle/common/utils/backtrace.hpp>
00043 #include <tuttle/common/exceptions.hpp>
00044 
00045 #include <boost/numeric/conversion/cast.hpp>
00046 #include <boost/lexical_cast.hpp>
00047 #include <boost/foreach.hpp>
00048 #include <boost/exception/diagnostic_information.hpp>
00049 
00050 #include <algorithm> // for find
00051 #include <iostream>
00052 #include <sstream>
00053 #include <string>
00054 
00055 /** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries. */
00056 namespace OFX {
00057 
00058 FramesNeededSetter::~FramesNeededSetter() {}
00059 RegionOfInterestSetter::~RegionOfInterestSetter() {}
00060 
00061 
00062 // globals to keep consistent data structures around.
00063 OFX::PluginFactoryArray plugIDs;
00064 //Put it all into a map, so we know when to delete what!
00065 struct OfxPlugInfo
00066 {
00067         OfxPlugInfo()
00068         : _factory(NULL)
00069         , _plug(NULL)
00070         {}
00071         OfxPlugInfo( OFX::PluginFactory* f, OfxPlugin* p )
00072         : _factory( f )
00073         , _plug( p )
00074         {}
00075         OFX::PluginFactory* _factory;
00076         OfxPlugin* _plug;
00077 };
00078 
00079 typedef std::map<std::string, OfxPlugInfo> OfxPlugInfoMap;
00080 typedef std::vector<OfxPlugin*> OfxPluginArray;
00081 
00082 namespace Private {
00083 OfxPlugInfoMap plugInfoMap;
00084 OfxPluginArray ofxPlugs;
00085 
00086 /** @brief the global host description */
00087 ImageEffectHostDescription gHostDescription;
00088 bool gHostDescriptionHasInit = false;
00089 
00090 
00091 /** @brief Keeps count of how many times load/unload have been called */
00092 int gLoadCount = 0;
00093 bool gHasInit = false;
00094 
00095 // Suite and host pointers
00096 OfxHost* gHost                      = NULL;
00097 OfxImageEffectSuiteV1* gEffectSuite = NULL;
00098 OfxPropertySuiteV1* gPropSuite      = NULL;
00099 OfxInteractSuiteV1* gInteractSuite  = NULL;
00100 OfxParameterSuiteV1* gParamSuite    = NULL;
00101 OfxMemorySuiteV1* gMemorySuite      = NULL;
00102 OfxMultiThreadSuiteV1* gThreadSuite = NULL;
00103 OfxMessageSuiteV1* gMessageSuite    = NULL;
00104 OfxProgressSuiteV1* gProgressSuite  = NULL;
00105 OfxTimeLineSuiteV1* gTimeLineSuite  = NULL;
00106 OfxParametricParameterSuiteV1* gParametricParameterSuite = NULL;
00107 NukeOfxCameraSuiteV1* gCameraParameterSuite = NULL;
00108 
00109 // @brief the set of descriptors, one per context used by kOfxActionDescribeInContext,
00110 //'eContextNone' is the one used by the kOfxActionDescribe
00111 EffectDescriptorMap gEffectDescriptors;
00112 } // namespace Private
00113 
00114 
00115 ImageEffectHostDescription* getImageEffectHostDescription()
00116 {
00117         if( Private::gHostDescriptionHasInit )
00118         return &Private::gHostDescription;
00119         return NULL;
00120 }
00121 
00122 
00123 /** @brief map a std::string to a context */
00124 EContext mapContextStringToEnum( const std::string& s )
00125 {
00126         if( s == kOfxImageEffectContextGenerator )
00127         return eContextGenerator;
00128         if( s == kOfxImageEffectContextFilter )
00129         return eContextFilter;
00130         if( s == kOfxImageEffectContextTransition )
00131         return eContextTransition;
00132         if( s == kOfxImageEffectContextPaint )
00133         return eContextPaint;
00134         if( s == kOfxImageEffectContextGeneral )
00135         return eContextGeneral;
00136         if( s == kOfxImageEffectContextRetimer )
00137         return eContextRetimer;
00138         if( s == kOfxImageEffectContextReader )
00139         return eContextReader;
00140         if( s == kOfxImageEffectContextWriter )
00141         return eContextWriter;
00142         OFX::Log::error( true, "Unknown image effect context '%s'", s.c_str() );
00143         BOOST_THROW_EXCEPTION( std::invalid_argument( s ) );
00144         return eContextGeneral;
00145 }
00146 
00147 /** @brief map a std::string to a context */
00148 const std::string mapContextEnumToString( const EContext s )
00149 {
00150         switch( s )
00151         {
00152         case eContextGenerator:
00153                 return kOfxImageEffectContextGenerator;
00154         case eContextFilter:
00155                 return kOfxImageEffectContextFilter;
00156         case eContextTransition:
00157                 return kOfxImageEffectContextTransition;
00158         case eContextPaint:
00159                 return kOfxImageEffectContextPaint;
00160         case eContextGeneral:
00161                 return kOfxImageEffectContextGeneral;
00162         case eContextRetimer:
00163                 return kOfxImageEffectContextRetimer;
00164         case eContextReader:
00165                 return kOfxImageEffectContextReader;
00166         case eContextWriter:
00167                 return kOfxImageEffectContextWriter;
00168         case eContextNone:
00169                 return "ContextNone...";
00170         }
00171         OFX::Log::error( true, "Unknown image effect context enum '%d'", (int)s );
00172         BOOST_THROW_EXCEPTION( std::invalid_argument( "Unknown image effect context enum." ) );
00173         return "";
00174 }
00175 
00176 const std::string mapMessageTypeEnumToString( const OFX::Message::EMessageType type )
00177 {
00178         if( type == OFX::Message::eMessageFatal )
00179         return kOfxMessageFatal;
00180         else if( type == OFX::Message::eMessageError )
00181         return kOfxMessageError;
00182         else if( type == OFX::Message::eMessageMessage )
00183         return kOfxMessageMessage;
00184         else if( type == OFX::Message::eMessageLog )
00185         return kOfxMessageLog;
00186         else if( type == OFX::Message::eMessageQuestion )
00187         return kOfxMessageQuestion;
00188         OFX::Log::error( true, "Unknown message type enum '%d'", type );
00189         return 0;
00190 }
00191 
00192 OFX::Message::EMessageReply mapMessageReplyStatusToEnum( const OfxStatus stat )
00193 {
00194         if( stat == kOfxStatOK )
00195         return OFX::Message::eMessageReplyOK;
00196         else if( stat == kOfxStatReplyYes )
00197         return OFX::Message::eMessageReplyYes;
00198         else if( stat == kOfxStatReplyNo )
00199         return OFX::Message::eMessageReplyNo;
00200         else if( stat == kOfxStatFailed )
00201         return OFX::Message::eMessageReplyFailed;
00202         OFX::Log::error( true, "Unknown message reply status value '%d'", stat );
00203         return OFX::Message::eMessageReplyFailed;
00204 }
00205 
00206 OfxStatus mapMessageReplyEnumToStatus( const OFX::Message::EMessageReply stat )
00207 {
00208         switch( stat )
00209         {
00210         case OFX::Message::eMessageReplyOK:
00211                 return kOfxStatOK;
00212         case OFX::Message::eMessageReplyYes:
00213                 return kOfxStatReplyYes;
00214         case OFX::Message::eMessageReplyNo:
00215                 return kOfxStatReplyNo;
00216         case OFX::Message::eMessageReplyFailed:
00217                 return kOfxStatFailed;
00218         }
00219         OFX::Log::error( true, "Unknown message reply status enum '%d'", stat );
00220         return kOfxStatFailed;
00221 }
00222 
00223 /** @brief map a std::string to a context */
00224 InstanceChangeReason mapInstanceChangedReasonStringToEnum( const std::string& s )
00225 {
00226         if( s == kOfxChangePluginEdited )
00227         return eChangePluginEdit;
00228         if( s == kOfxChangeUserEdited )
00229         return eChangeUserEdit;
00230         if( s == kOfxChangeTime )
00231         return eChangeTime;
00232         OFX::Log::error( true, "Unknown instance changed reason '%s'", s.c_str() );
00233         BOOST_THROW_EXCEPTION( std::invalid_argument( s ) );
00234         return eChangePluginEdit;
00235 }
00236 
00237 /** @brief turns a bit depth string into and enum */
00238 EBitDepth mapBitDepthStringToEnum( const std::string& str )
00239 {
00240         if( str == kOfxBitDepthByte )
00241         {
00242         return eBitDepthUByte;
00243         }
00244         else if( str == kOfxBitDepthShort )
00245         {
00246         return eBitDepthUShort;
00247         }
00248         else if( str == kOfxBitDepthFloat )
00249         {
00250         return eBitDepthFloat;
00251         }
00252         else if( str == kOfxBitDepthNone )
00253         {
00254         return eBitDepthNone;
00255         }
00256         else
00257         {
00258         return eBitDepthCustom;
00259         }
00260 }
00261 
00262 const std::string mapBitDepthEnumToString( const EBitDepth e )
00263 {
00264         switch(e)
00265         {
00266         case eBitDepthUByte:
00267                 return kOfxBitDepthByte;
00268         case eBitDepthUShort:
00269                 return kOfxBitDepthShort;
00270         case eBitDepthFloat:
00271                 return kOfxBitDepthFloat;
00272         case eBitDepthNone:
00273                 return kOfxBitDepthNone;
00274         case eBitDepthCustom:
00275                 return "eBitDepthCustom";
00276         }
00277         BOOST_THROW_EXCEPTION( std::invalid_argument( "BitDepth enum: " + boost::lexical_cast<std::string>(e) ) );
00278         return kOfxBitDepthNone;
00279 }
00280 
00281 /** @brief turns a pixel component string into and enum */
00282 EPixelComponent mapPixelComponentStringToEnum( const std::string& str )
00283 {
00284         if( str == kOfxImageComponentRGBA )
00285         {
00286         return ePixelComponentRGBA;
00287         }
00288         else if( str == kOfxImageComponentRGB )
00289         {
00290         return ePixelComponentRGB;
00291         }
00292         else if( str == kOfxImageComponentAlpha )
00293         {
00294         return ePixelComponentAlpha;
00295         }
00296         else if( str == kOfxImageComponentNone )
00297         {
00298         return ePixelComponentNone;
00299         }
00300         else
00301         {
00302         return ePixelComponentCustom;
00303         }
00304 }
00305 
00306 std::string mapPixelComponentEnumToString( const EPixelComponent e )
00307 {
00308         switch(e)
00309         {
00310         case ePixelComponentRGBA:
00311                 return kOfxImageComponentRGBA;
00312         case ePixelComponentRGB:
00313                 return kOfxImageComponentRGB;
00314         case ePixelComponentAlpha:
00315                 return kOfxImageComponentAlpha;
00316         case ePixelComponentNone:
00317                 return kOfxImageComponentNone;
00318         case ePixelComponentCustom:
00319                 return "ePixelComponentCustom";
00320         }
00321         BOOST_THROW_EXCEPTION( std::invalid_argument( "EPixelComponent: " + boost::lexical_cast<std::string>(e) ) );
00322 }
00323 
00324 /** @brief turns a premultiplication string into and enum */
00325 EPreMultiplication mapPreMultiplicationStringToEnum( const std::string& str )
00326 {
00327         if( str == kOfxImageOpaque )
00328         {
00329         return eImageOpaque;
00330         }
00331         else if( str == kOfxImagePreMultiplied )
00332         {
00333         return eImagePreMultiplied;
00334         }
00335         else if( str == kOfxImageUnPreMultiplied )
00336         {
00337         return eImageUnPreMultiplied;
00338         }
00339         BOOST_THROW_EXCEPTION( std::invalid_argument( str ) );
00340         return eImageOpaque;
00341 }
00342 
00343 std::string mapPreMultiplicationEnumToString( const EPreMultiplication e )
00344 {
00345         switch( e )
00346         {
00347         case eImageOpaque:
00348                 return kOfxImageOpaque;
00349         case eImagePreMultiplied:
00350                 return kOfxImagePreMultiplied;
00351         case eImageUnPreMultiplied:
00352                 return kOfxImageUnPreMultiplied;
00353         }
00354         BOOST_THROW_EXCEPTION( std::invalid_argument( "PreMultiplicationEnum: " + boost::lexical_cast<std::string>(e) ) );
00355         return "";
00356 }
00357 
00358 /** @brief turns a field string into and enum */
00359 EField mapFieldStringToEnum( const std::string& str )
00360 {
00361         if( str == kOfxImageFieldNone )
00362         {
00363         return eFieldNone;
00364         }
00365         else if( str == kOfxImageFieldBoth )
00366         {
00367         return eFieldBoth;
00368         }
00369         else if( str == kOfxImageFieldLower )
00370         {
00371         return eFieldLower;
00372         }
00373         else if( str == kOfxImageFieldUpper )
00374         {
00375         return eFieldUpper;
00376         }
00377         BOOST_THROW_EXCEPTION( std::invalid_argument( str ) );
00378         return eFieldNone;
00379 }
00380 
00381 std::string mapFieldEnumToString( const EField e )
00382 {
00383         switch( e )
00384         {
00385         case eFieldNone:
00386                 return kOfxImageFieldNone;
00387         case eFieldBoth:
00388                 return kOfxImageFieldBoth;
00389         case eFieldLower:
00390                 return kOfxImageFieldLower;
00391         case eFieldUpper:
00392                 return kOfxImageFieldUpper;
00393         }
00394         BOOST_THROW_EXCEPTION( std::invalid_argument( boost::lexical_cast<std::string>(e) ) );
00395         return "";
00396 }
00397 
00398 ////////////////////////////////////////////////////////////////////////////////
00399 // clip descriptor
00400 
00401 /** @brief hidden constructor */
00402 ClipDescriptor::ClipDescriptor( const std::string& name, OfxPropertySetHandle props )
00403         : _clipName( name ),
00404         _clipProps( props )
00405 {
00406         OFX::Validation::validateClipDescriptorProperties( props );
00407 }
00408 
00409 /** @brief set the label properties */
00410 void ClipDescriptor::setLabels( const std::string& label, const std::string& shortLabel, const std::string& longLabel )
00411 {
00412         _clipProps.propSetString( kOfxPropLabel, label );
00413         _clipProps.propSetString( kOfxPropShortLabel, shortLabel, false );
00414         _clipProps.propSetString( kOfxPropLongLabel, longLabel, false );
00415 }
00416 
00417 /** @brief set how fielded images are extracted from the clip defaults to eFieldExtractDoubled */
00418 void ClipDescriptor::setFieldExtraction( EFieldExtraction v )
00419 {
00420         switch( v )
00421         {
00422         case eFieldExtractBoth:
00423                 _clipProps.propSetString( kOfxImageClipPropFieldExtraction, kOfxImageFieldBoth );
00424                 break;
00425 
00426         case eFieldExtractSingle:
00427                 _clipProps.propSetString( kOfxImageClipPropFieldExtraction, kOfxImageFieldSingle );
00428                 break;
00429 
00430         case eFieldExtractDoubled:
00431                 _clipProps.propSetString( kOfxImageClipPropFieldExtraction, kOfxImageFieldDoubled );
00432                 break;
00433         }
00434 }
00435 
00436 /** @brief set which components are supported, defaults to none set, this must be called at least once! */
00437 void ClipDescriptor::addSupportedComponent( EPixelComponent v )
00438 {
00439         int n = _clipProps.propGetDimension( kOfxImageEffectPropSupportedComponents );
00440 
00441         switch( v )
00442         {
00443         case ePixelComponentRGBA:
00444                 _clipProps.propSetString( kOfxImageEffectPropSupportedComponents, kOfxImageComponentRGBA, n );
00445                 break;
00446         case ePixelComponentRGB:
00447                 _clipProps.propSetString( kOfxImageEffectPropSupportedComponents, kOfxImageComponentRGB, n );
00448                 break;
00449         case ePixelComponentAlpha:
00450                 _clipProps.propSetString( kOfxImageEffectPropSupportedComponents, kOfxImageComponentAlpha, n );
00451                 break;
00452         case ePixelComponentCustom:
00453                 break;
00454         case ePixelComponentNone:
00455                 _clipProps.propSetString( kOfxImageEffectPropSupportedComponents, kOfxImageComponentNone, n );
00456                 break;
00457         }
00458 }
00459 
00460 /** @brief set which components are supported, defaults to none set, this must be called at least once! */
00461 void ClipDescriptor::addSupportedComponent( const std::string& comp )
00462 {
00463         int n = _clipProps.propGetDimension( kOfxImageEffectPropSupportedComponents );
00464 
00465         _clipProps.propSetString( kOfxImageEffectPropSupportedComponents, comp, n );
00466 
00467 }
00468 
00469 /** @brief say whether we are going to do random temporal access on this clip, defaults to false */
00470 void ClipDescriptor::setTemporalClipAccess( bool v )
00471 {
00472         _clipProps.propSetInt( kOfxImageEffectPropTemporalClipAccess, int(v) );
00473 }
00474 
00475 /** @brief say whether if the clip is optional, defaults to false */
00476 void ClipDescriptor::setOptional( bool v )
00477 {
00478         _clipProps.propSetInt( kOfxImageClipPropOptional, int(v) );
00479 }
00480 
00481 /** @brief say whether this clip supports tiling, defaults to true */
00482 void ClipDescriptor::setSupportsTiles( bool v )
00483 {
00484         _clipProps.propSetInt( kOfxImageEffectPropSupportsTiles, int(v) );
00485 }
00486 
00487 /** @brief say whether this clip is a 'mask', so the host can know to replace with a roto or similar, defaults to false */
00488 void ClipDescriptor::setIsMask( bool v )
00489 {
00490         _clipProps.propSetInt( kOfxImageClipPropIsMask, int(v) );
00491 }
00492 
00493 ////////////////////////////////////////////////////////////////////////////////
00494 // image effect descriptor
00495 
00496 /** @brief effect descriptor ctor */
00497 ImageEffectDescriptor::ImageEffectDescriptor( OfxImageEffectHandle handle )
00498         : _effectHandle( handle )
00499 {
00500         // fetch the property set handle of the effect
00501         OfxPropertySetHandle props;
00502         OfxStatus stat = OFX::Private::gEffectSuite->getPropertySet( handle, &props );
00503 
00504         throwSuiteStatusException( stat );
00505         _effectProps.propSetHandle( props );
00506 
00507         OFX::Validation::validatePluginDescriptorProperties( props );
00508 
00509         // fetch the param set handle and set it in our ParamSetDescriptor base
00510         OfxParamSetHandle paramSetHandle;
00511         stat = OFX::Private::gEffectSuite->getParamSet( handle, &paramSetHandle );
00512         throwSuiteStatusException( stat );
00513         setOfxParamSetHandle( paramSetHandle );
00514 }
00515 
00516 /** @brief dtor */
00517 ImageEffectDescriptor::~ImageEffectDescriptor()
00518 {
00519         // delete any clip descriptors we may have constructed
00520         std::map<std::string, ClipDescriptor*>::iterator iter;
00521         for( iter = _definedClips.begin(); iter != _definedClips.end(); ++iter )
00522         {
00523         if( iter->second )
00524         {
00525                 delete iter->second;
00526                 iter->second = NULL;
00527         }
00528         }
00529 }
00530 
00531 /** @brief, set the label properties in a plugin */
00532 void ImageEffectDescriptor::setLabels( const std::string& label, const std::string& shortLabel, const std::string& longLabel )
00533 {
00534         _effectProps.propSetString( kOfxPropLabel, label );
00535         _effectProps.propSetString( kOfxPropShortLabel, shortLabel, false );
00536         _effectProps.propSetString( kOfxPropLongLabel, longLabel, false );
00537 }
00538 
00539 void ImageEffectDescriptor::setDescription( const std::string& description )
00540 {
00541         // added in openfx API 1.2, so do not throw if unknown by the host
00542         _effectProps.propSetString( kOfxPropPluginDescription, description, false );
00543 }
00544 
00545 /** @brief Set the plugin grouping */
00546 void ImageEffectDescriptor::setPluginGrouping( const std::string& group )
00547 {
00548         _effectProps.propSetString( kOfxImageEffectPluginPropGrouping, group );
00549 }
00550 
00551 /** @brief Add a context to those supported */
00552 void ImageEffectDescriptor::addSupportedContext( EContext v )
00553 {
00554         int n = _effectProps.propGetDimension( kOfxImageEffectPropSupportedContexts );
00555 
00556         switch( v )
00557         {
00558         case eContextGenerator:
00559                 _effectProps.propSetString( kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGenerator, n );
00560                 break;
00561         case eContextFilter:
00562                 _effectProps.propSetString( kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextFilter, n );
00563                 break;
00564         case eContextTransition:
00565                 _effectProps.propSetString( kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextTransition, n );
00566                 break;
00567         case eContextPaint:
00568                 _effectProps.propSetString( kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextPaint, n );
00569                 break;
00570         case eContextGeneral:
00571                 _effectProps.propSetString( kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextGeneral, n );
00572                 break;
00573         case eContextRetimer:
00574                 _effectProps.propSetString( kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextRetimer, n );
00575                 break;
00576         case eContextReader:
00577                 _effectProps.propSetString( kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextReader, n );
00578                 break;
00579         case eContextWriter:
00580                 _effectProps.propSetString( kOfxImageEffectPropSupportedContexts, kOfxImageEffectContextWriter, n );
00581                 break;
00582         case eContextNone:
00583                 break;
00584         }
00585 }
00586 
00587 void ImageEffectDescriptor::setOverlayInteractDescriptor(EffectInteractWrap* desc)
00588 {
00589         _overlayDescriptor.reset( desc );
00590         if( OFX::Private::gHostDescription.supportsOverlays && desc->getMainEntry() )
00591         _effectProps.propSetPointer( kOfxImageEffectPluginPropOverlayInteractV1, (void*)desc->getMainEntry() );
00592 }
00593 
00594 /** @brief Add a pixel depth to those supported */
00595 void ImageEffectDescriptor::addSupportedBitDepth( EBitDepth v )
00596 {
00597         int n = _effectProps.propGetDimension( kOfxImageEffectPropSupportedPixelDepths );
00598 
00599         switch( v )
00600         {
00601         case eBitDepthUByte:
00602                 _effectProps.propSetString( kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthByte, n );
00603                 break;
00604         case eBitDepthUShort:
00605                 _effectProps.propSetString( kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthShort, n );
00606                 break;
00607         case eBitDepthFloat:
00608                 _effectProps.propSetString( kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthFloat, n );
00609                 break;
00610         case eBitDepthNone:
00611                 _effectProps.propSetString( kOfxImageEffectPropSupportedPixelDepths, kOfxBitDepthNone, n );
00612                 break;
00613         case eBitDepthCustom:
00614                 // what the good way ?
00615                 break;
00616         }
00617 }
00618 
00619 /** @brief Add a file extension to those supported */
00620 void ImageEffectDescriptor::addSupportedExtension( const std::string& extension )
00621 {
00622         // only Tuttle support this property ( out of standard )
00623         if( OFX::Private::gHostDescription.hostName == "TuttleOfx" )
00624         {
00625                 const int n = _effectProps.propGetDimension( kTuttleOfxImageEffectPropSupportedExtensions );
00626                 _effectProps.propSetString( kTuttleOfxImageEffectPropSupportedExtensions, extension, n );
00627         }
00628 }
00629 
00630 void ImageEffectDescriptor::addSupportedExtensions( const std::vector<std::string>& extensions )
00631 {
00632         // only Tuttle support this property ( out of standard )
00633         if( OFX::Private::gHostDescription.hostName == "TuttleOfx" )
00634         {
00635                 int n = _effectProps.propGetDimension( kTuttleOfxImageEffectPropSupportedExtensions );
00636 
00637                 BOOST_FOREACH( const std::string& ext, extensions )
00638                 {
00639                         _effectProps.propSetString( kTuttleOfxImageEffectPropSupportedExtensions, ext, n++ );
00640                 }
00641         }
00642 }
00643 
00644 /** @brief Is the plugin single instance only ? */
00645 void ImageEffectDescriptor::setSingleInstance( bool v )
00646 {
00647         _effectProps.propSetInt( kOfxImageEffectPluginPropSingleInstance, int(v) );
00648 }
00649 
00650 /** @brief Does the plugin expect the host to perform per frame SMP threading */
00651 void ImageEffectDescriptor::setHostFrameThreading( bool v )
00652 {
00653         _effectProps.propSetInt( kOfxImageEffectPluginPropHostFrameThreading, int(v) );
00654 }
00655 
00656 /** @brief Does the plugin support multi resolution images */
00657 void ImageEffectDescriptor::setSupportsMultiResolution( bool v )
00658 {
00659         _effectProps.propSetInt( kOfxImageEffectPropSupportsMultiResolution, int(v) );
00660 }
00661 
00662 /** @brief Does the plugin support image tiling */
00663 void ImageEffectDescriptor::setSupportsTiles( bool v )
00664 {
00665         _effectProps.propSetInt( kOfxImageEffectPropSupportsTiles, int(v) );
00666 }
00667 
00668 /** @brief Does the plugin perform temporal clip access */
00669 void ImageEffectDescriptor::setTemporalClipAccess( bool v )
00670 {
00671         _effectProps.propSetInt( kOfxImageEffectPropTemporalClipAccess, int(v) );
00672 }
00673 
00674 /** @brief Does the plugin want to have render called twice per frame in all circumanstances for fielded images ? */
00675 void ImageEffectDescriptor::setRenderTwiceAlways( bool v )
00676 {
00677         _effectProps.propSetInt( kOfxImageEffectPluginPropFieldRenderTwiceAlways, int(v) );
00678 }
00679 
00680 /** @brief Does the plugin support inputs and output clips of differing depths */
00681 void ImageEffectDescriptor::setSupportsMultipleClipDepths( bool v )
00682 {
00683         _effectProps.propSetInt( kOfxImageEffectPropSupportsMultipleClipDepths, int(v) );
00684 }
00685 
00686 /** @brief Does the plugin support inputs and output clips of pixel aspect ratios */
00687 void ImageEffectDescriptor::setSupportsMultipleClipPARs( bool v )
00688 {
00689         _effectProps.propSetInt( kOfxImageEffectPropSupportsMultipleClipPARs, int(v) );
00690 }
00691 
00692 /** @brief What kind of thread safety does the plugin have */
00693 void ImageEffectDescriptor::setRenderThreadSafety( ERenderSafety v )
00694 {
00695         switch( v )
00696         {
00697         case eRenderUnsafe:
00698                 _effectProps.propSetString( kOfxImageEffectPluginRenderThreadSafety, kOfxImageEffectRenderUnsafe );
00699                 break;
00700         case eRenderInstanceSafe:
00701                 _effectProps.propSetString( kOfxImageEffectPluginRenderThreadSafety, kOfxImageEffectRenderInstanceSafe );
00702                 break;
00703         case eRenderFullySafe:
00704                 _effectProps.propSetString( kOfxImageEffectPluginRenderThreadSafety, kOfxImageEffectRenderFullySafe );
00705                 break;
00706         }
00707 }
00708 
00709 /** @brief If the slave param changes the clip preferences need to be re-evaluated */
00710 void ImageEffectDescriptor::addClipPreferencesSlaveParam( ParamDescriptor& p )
00711 {
00712         int n = _effectProps.propGetDimension( kOfxImageEffectPropClipPreferencesSlaveParam );
00713 
00714         _effectProps.propSetString( kOfxImageEffectPropClipPreferencesSlaveParam, p.getName(), n );
00715 }
00716 
00717 /** @brief Create a clip, only callable from describe in context */
00718 ClipDescriptor* ImageEffectDescriptor::defineClip( const std::string& name )
00719 {
00720         // do we have the clip already
00721         std::map<std::string, ClipDescriptor*>::const_iterator search;
00722         search = _definedClips.find( name );
00723         if( search != _definedClips.end() )
00724         return search->second;
00725 
00726         // no, so make it
00727         OfxPropertySetHandle propSet;
00728         OfxStatus stat = OFX::Private::gEffectSuite->clipDefine( _effectHandle, name.c_str(), &propSet );
00729         if( stat == kOfxStatOK )
00730         {
00731         ClipDescriptor* clip = new ClipDescriptor( name, propSet );
00732 
00733         _definedClips[name]            = clip;
00734         _clipComponentsPropNames[name] = std::string( "OfxImageClipPropComponents_" ) + name;
00735         _clipDepthPropNames[name]      = std::string( "OfxImageClipPropDepth_" ) + name;
00736         _clipPARPropNames[name]        = std::string( "OfxImageClipPropPAR_" ) + name;
00737         _clipROIPropNames[name]        = std::string( "OfxImageClipPropRoI_" ) + name;
00738         _clipFrameRangePropNames[name] = std::string( "OfxImageClipPropFrameRange_" ) + name;
00739 
00740         return clip;
00741         }
00742         else
00743         return NULL;
00744 }
00745 
00746 ////////////////////////////////////////////////////////////////////////////////
00747 // wraps up an image
00748 Image::Image( OfxPropertySetHandle props )
00749         : _imageProps( props )
00750 {
00751         OFX::Validation::validateImageProperties( props );
00752 
00753         // and fetch all the properties
00754         _pixelData = _imageProps.propGetPointer( kOfxImagePropData );
00755 
00756         _rowDistanceBytes = _imageProps.propGetInt( kOfxImagePropRowBytes );
00757         _pixelAspectRatio = _imageProps.propGetDouble( kOfxImagePropPixelAspectRatio );
00758 
00759         std::string str = _imageProps.propGetString( kOfxImageEffectPropComponents );
00760         _pixelComponents = mapPixelComponentStringToEnum( str );
00761 
00762         str         = _imageProps.propGetString( kOfxImageEffectPropPixelDepth );
00763         _pixelDepth = mapBitDepthStringToEnum( str );
00764 
00765         // compute bytes per pixel
00766         _pixelBytes = 0;
00767         switch( _pixelComponents )
00768         {
00769         case ePixelComponentRGBA: _pixelBytes   = 4; break;
00770         case ePixelComponentRGB: _pixelBytes   = 3; break;
00771         case ePixelComponentAlpha: _pixelBytes  = 1; break;
00772         case ePixelComponentCustom: _pixelBytes = 0; break;
00773         case ePixelComponentNone: _pixelBytes   = 0; break;
00774         }
00775 
00776         switch( _pixelDepth )
00777         {
00778         case eBitDepthUByte: _pixelBytes  *= 1; break;
00779         case eBitDepthUShort: _pixelBytes *= 2; break;
00780         case eBitDepthFloat: _pixelBytes  *= 4; break;
00781         case eBitDepthCustom: /* what the good way ? */ break;
00782         case eBitDepthNone: _pixelBytes = 0; break;
00783         }
00784 
00785         str                = _imageProps.propGetString( kOfxImageEffectPropPreMultiplication );
00786         _preMultiplication =  mapPreMultiplicationStringToEnum( str );
00787 
00788         _regionOfDefinition.x1 = _imageProps.propGetInt( kOfxImagePropRegionOfDefinition, 0 );
00789         _regionOfDefinition.y1 = _imageProps.propGetInt( kOfxImagePropRegionOfDefinition, 1 );
00790         _regionOfDefinition.x2 = _imageProps.propGetInt( kOfxImagePropRegionOfDefinition, 2 );
00791         _regionOfDefinition.y2 = _imageProps.propGetInt( kOfxImagePropRegionOfDefinition, 3 );
00792 
00793         _bounds.x1 = _imageProps.propGetInt( kOfxImagePropBounds, 0 );
00794         _bounds.y1 = _imageProps.propGetInt( kOfxImagePropBounds, 1 );
00795         _bounds.x2 = _imageProps.propGetInt( kOfxImagePropBounds, 2 );
00796         _bounds.y2 = _imageProps.propGetInt( kOfxImagePropBounds, 3 );
00797 
00798         str = _imageProps.propGetString( kOfxImagePropField );
00799         if( str == kOfxImageFieldNone )
00800         {
00801         _field = eFieldNone;
00802         }
00803         else if( str == kOfxImageFieldBoth )
00804         {
00805         _field = eFieldBoth;
00806         }
00807         else if( str == kOfxImageFieldLower )
00808         {
00809         _field = eFieldLower;
00810         }
00811         else if( str == kOfxImageFieldUpper )
00812         {
00813         _field = eFieldLower;
00814         }
00815         else
00816         {
00817         OFX::Log::error( true, "Unknown field state '%s' reported on an image", str.c_str() );
00818         _field = eFieldNone;
00819         }
00820 
00821         _uniqueID = _imageProps.propGetString( kOfxImagePropUniqueIdentifier );
00822 
00823         //      std::string tuttleFullName = _imageProps.propGetString( "TuttleFullName" );
00824         //      TUTTLE_LOG_TRACE("tuttleFullName: " << tuttleFullName );
00825 
00826         _renderScale.x = _imageProps.propGetDouble( kOfxImageEffectPropRenderScale, 0 );
00827         _renderScale.y = _imageProps.propGetDouble( kOfxImageEffectPropRenderScale, 1 );
00828 
00829         //std::cout << "IMAGE + " << _uniqueID << std::endl;
00830 }
00831 
00832 Image::~Image()
00833 {
00834         //std::cout << "IMAGE - " << _uniqueID << std::endl;
00835         OFX::Private::gEffectSuite->clipReleaseImage( _imageProps.propSetHandle() );
00836 }
00837 
00838 std::size_t Image::getPixelBytes() const
00839 {
00840         std::size_t pixelBytes = 0;
00841 
00842         switch( getPixelDepth() )
00843         {
00844                 case OFX::eBitDepthCustom:
00845                 case OFX::eBitDepthNone:
00846                         return 0; // Unknown
00847                 case OFX::eBitDepthUByte: pixelBytes = 1;
00848                         break;
00849                 case OFX::eBitDepthUShort: pixelBytes = 2;
00850                         break;
00851                 case OFX::eBitDepthFloat: pixelBytes = 4;
00852                         break;
00853         }
00854 
00855         switch( getPixelComponents() )
00856         {
00857                 case OFX::ePixelComponentAlpha: break; // pixelSize * 1
00858                 case OFX::ePixelComponentRGB: pixelBytes *= 3;
00859                         break;
00860                 case OFX::ePixelComponentRGBA: pixelBytes *= 4;
00861                         break;
00862                 default: break;
00863         }
00864         return pixelBytes;
00865 }
00866 
00867 std::size_t Image::getBoundsRowDataBytes() const
00868 {
00869         return getPixelBytes() * getBoundsSize().x;
00870 }
00871 
00872 std::size_t Image::getBoundsNbPixels() const
00873 {
00874         const OfxPointI s = getBoundsSize();
00875         return s.x * s.y;
00876 }
00877 
00878 std::size_t Image::getBoundsImageDataBytes() const
00879 {
00880         return getPixelBytes() * getBoundsNbPixels();
00881 }
00882 
00883 /** @brief return a pixel pointer
00884 *
00885 * No attempt made to be uber efficient here.
00886 */
00887 void* Image::getPixelAddress( int x, int y )
00888 {
00889         // are we in the image bounds
00890         BOOST_ASSERT( x >= _bounds.x1 && x < _bounds.x2 && y >= _bounds.y1 && y < _bounds.y2 && _pixelBytes != 0 );
00891 
00892         char* pix = ( char* )( ( (char*) _pixelData ) + ( y - _bounds.y1 ) * _rowDistanceBytes );
00893         pix += ( x - _bounds.x1 ) * _pixelBytes;
00894         return (void*) pix;
00895 }
00896 
00897 ////////////////////////////////////////////////////////////////////////////////
00898 // clip instance
00899 
00900 /** @brief hidden constructor */
00901 Clip::Clip( ImageEffect* effect, const std::string& name, OfxImageClipHandle handle, OfxPropertySetHandle props )
00902         : _clipName( name ),
00903         _clipProps( props ),
00904         _clipHandle( handle ),
00905         _effect( effect )
00906 {
00907         OFX::Validation::validateClipInstanceProperties( _clipProps );
00908 }
00909 
00910 /** @brief fetch the labels */
00911 void Clip::getLabels( std::string& label, std::string& shortLabel, std::string& longLabel ) const
00912 {
00913         label      = _clipProps.propGetString( kOfxPropLabel );
00914         shortLabel = _clipProps.propGetString( kOfxPropShortLabel, false );
00915         longLabel  = _clipProps.propGetString( kOfxPropLongLabel, false );
00916 }
00917 
00918 /** @brief get the pixel depth */
00919 EBitDepth Clip::getPixelDepth( void ) const
00920 {
00921         std::string str = _clipProps.propGetString( kOfxImageEffectPropPixelDepth );
00922         EBitDepth bitDepth;
00923 
00924         try
00925         {
00926         bitDepth = mapBitDepthStringToEnum( str );
00927         if( bitDepth == eBitDepthNone && isConnected() )
00928         {
00929                 OFX::Log::error( true, "Clip %s is connected and has no pixel depth.", _clipName.c_str() );
00930         }
00931         }
00932         // gone wrong ?
00933         catch( std::invalid_argument& )
00934         {
00935         OFX::Log::error( true, "Unknown pixel depth property '%s' reported on clip '%s'", str.c_str(), _clipName.c_str() );
00936         bitDepth = eBitDepthNone;
00937         }
00938         return bitDepth;
00939 }
00940 
00941 /** @brief get the components in the image */
00942 EPixelComponent Clip::getPixelComponents( void ) const
00943 {
00944         std::string str = _clipProps.propGetString( kOfxImageEffectPropComponents );
00945         EPixelComponent pix;
00946 
00947         try
00948         {
00949         pix = mapPixelComponentStringToEnum( str );
00950         if( pix == ePixelComponentNone && isConnected() )
00951         {
00952                 OFX::Log::error( true, "Clip %s is connected and has no pixel component type!", _clipName.c_str() );
00953         }
00954         }
00955         // gone wrong ?
00956         catch( std::invalid_argument& )
00957         {
00958         OFX::Log::error( true, "Unknown  pixel component type '%s' reported on clip '%s'", str.c_str(), _clipName.c_str() );
00959         pix = ePixelComponentNone;
00960         }
00961         return pix;
00962 }
00963 
00964 /** @brief what is the actual pixel depth of the clip */
00965 EBitDepth Clip::getUnmappedPixelDepth( void ) const
00966 {
00967         std::string str = _clipProps.propGetString( kOfxImageClipPropUnmappedPixelDepth );
00968         EBitDepth bitDepth;
00969 
00970         try
00971         {
00972         bitDepth = mapBitDepthStringToEnum( str );
00973         if( bitDepth == eBitDepthNone && !isConnected() )
00974         {
00975                 OFX::Log::error( true, "Clip %s is connected and has no unmapped pixel depth.", _clipName.c_str() );
00976         }
00977         }
00978         // gone wrong ?
00979         catch( std::invalid_argument& )
00980         {
00981         OFX::Log::error( true, "Unknown unmapped pixel depth property '%s' reported on clip '%s'", str.c_str(), _clipName.c_str() );
00982         bitDepth = eBitDepthNone;
00983         }
00984         return bitDepth;
00985 }
00986 
00987 /** @brief what is the component type of the clip */
00988 EPixelComponent Clip::getUnmappedPixelComponents( void ) const
00989 {
00990         std::string str = _clipProps.propGetString( kOfxImageClipPropUnmappedComponents );
00991         EPixelComponent pix;
00992 
00993         try
00994         {
00995         pix = mapPixelComponentStringToEnum( str );
00996         if( pix == ePixelComponentNone && !isConnected() )
00997         {
00998                 OFX::Log::error( true, "Clip %s is connected and has no unmapped pixel component type!", _clipName.c_str() );
00999         }
01000         }
01001         // gone wrong ?
01002         catch( std::invalid_argument& )
01003         {
01004         OFX::Log::error( true, "Unknown unmapped pixel component type '%s' reported on clip '%s'", str.c_str(), _clipName.c_str() );
01005         pix = ePixelComponentNone;
01006         }
01007         return pix;
01008 }
01009 
01010 /** @brief get the components in the image */
01011 EPreMultiplication Clip::getPreMultiplication( void ) const
01012 {
01013         std::string str = _clipProps.propGetString( kOfxImageEffectPropPreMultiplication );
01014         EPreMultiplication premult;
01015 
01016         try
01017         {
01018         premult = mapPreMultiplicationStringToEnum( str );
01019         }
01020         // gone wrong ?
01021         catch( std::invalid_argument& )
01022         {
01023         OFX::Log::error( true, "Unknown premultiplication type '%s' reported on clip %s!", str.c_str(), _clipName.c_str() );
01024         premult = eImageOpaque;
01025         }
01026         return premult;
01027 }
01028 
01029 /** @brief which spatial field comes first temporally */
01030 EField Clip::getFieldOrder( void ) const
01031 {
01032         std::string str = _clipProps.propGetString( kOfxImageClipPropFieldOrder );
01033         EField field;
01034 
01035         try
01036         {
01037         field = mapFieldStringToEnum( str );
01038         OFX::Log::error( field != eFieldNone && field != eFieldLower && field != eFieldUpper,
01039                         "Field order '%s' reported on a clip %s is invalid, it must be none, lower or upper.", str.c_str(), _clipName.c_str() );
01040         }
01041         // gone wrong ?
01042         catch( std::invalid_argument& )
01043         {
01044         OFX::Log::error( true, "Unknown field order '%s' reported on a clip %s.", str.c_str(), _clipName.c_str() );
01045         field = eFieldNone;
01046         }
01047         return field;
01048 }
01049 
01050 /** @brief is the clip connected */
01051 bool Clip::isConnected( void ) const
01052 {
01053         return _clipProps.propGetInt( kOfxImageClipPropConnected ) != 0;
01054 }
01055 
01056 /** @brief can the clip be continuously sampled */
01057 bool Clip::hasContinuousSamples( void ) const
01058 {
01059         return _clipProps.propGetInt( kOfxImageClipPropContinuousSamples ) != 0;
01060 }
01061 
01062 /** @brief get the scale factor that has been applied to this clip */
01063 double Clip::getPixelAspectRatio( void ) const
01064 {
01065     try {
01066             return _clipProps.propGetDouble( kOfxImagePropPixelAspectRatio );
01067     }
01068     catch(...)
01069     {
01070         return 1.0;  // This error could happen in Eyeon Fusion.
01071     }
01072 }
01073 
01074 /** @brief get the frame rate, in frames per second on this clip, after any clip preferences have been applied */
01075 double Clip::getFrameRate( void ) const
01076 {
01077         return _clipProps.propGetDouble( kOfxImageEffectPropFrameRate );
01078 }
01079 
01080 /** @brief return the range of frames over which this clip has images, after any clip preferences have been applied */
01081 OfxRangeD Clip::getFrameRange( void ) const
01082 {
01083         OfxRangeD v;
01084 
01085         v.min = _clipProps.propGetDouble( kOfxImageEffectPropFrameRange, 0 );
01086         v.max = _clipProps.propGetDouble( kOfxImageEffectPropFrameRange, 1 );
01087         return v;
01088 }
01089 
01090 /** @brief get the frame rate, in frames per second on this clip, before any clip preferences have been applied */
01091 double Clip::getUnmappedFrameRate( void ) const
01092 {
01093         return _clipProps.propGetDouble( kOfxImageEffectPropUnmappedFrameRate );
01094 }
01095 
01096 /** @brief return the range of frames over which this clip has images, before any clip preferences have been applied */
01097 OfxRangeD Clip::getUnmappedFrameRange( void ) const
01098 {
01099         OfxRangeD v;
01100 
01101         v.min = _clipProps.propGetDouble( kOfxImageEffectPropUnmappedFrameRange, 0 );
01102         v.max = _clipProps.propGetDouble( kOfxImageEffectPropUnmappedFrameRange, 1 );
01103         return v;
01104 }
01105 
01106 /** @brief get the RoD for this clip in the cannonical coordinate system */
01107 OfxRectD Clip::getCanonicalRod( const OfxTime t ) const
01108 {
01109         OfxRectD bounds;
01110         OfxStatus stat = OFX::Private::gEffectSuite->clipGetRegionOfDefinition( _clipHandle, t, &bounds );
01111 
01112         if( stat == kOfxStatFailed )
01113         {
01114         bounds.x1 = bounds.x2 = bounds.y1 = bounds.y2 = 0;
01115         }
01116         throwSuiteStatusException( stat );
01117         return bounds;
01118 }
01119 
01120 OfxRectD Clip::getCanonicalRod( const OfxTime t, const OfxPointD& renderScale ) const
01121 {
01122         OfxRectD rod = getCanonicalRod( t );
01123         rod.x1 *= renderScale.x;
01124         rod.y1 *= renderScale.y;
01125         rod.x2 *= renderScale.x;
01126         rod.y2 *= renderScale.y;
01127         return rod;
01128 }
01129 
01130 /** @brief get the RoD for this clip in pixel space */
01131 OfxRectI Clip::getPixelRod( const OfxTime t ) const
01132 {
01133         OfxRectD rod = getCanonicalRod(t);
01134         double ratio = getPixelAspectRatio();
01135         if( ratio == 0.0 )
01136                 ratio = 1.0;
01137 
01138         OfxRectI pixRod;
01139         pixRod.x1 = boost::numeric_cast<int>(rod.x1 / ratio);
01140         pixRod.y1 = boost::numeric_cast<int>(rod.y1);
01141         pixRod.x2 = boost::numeric_cast<int>(std::ceil(rod.x2 / ratio));
01142         pixRod.y2 = boost::numeric_cast<int>(std::ceil(rod.y2));
01143 
01144         return pixRod;
01145 }
01146 
01147 OfxRectI Clip::getPixelRod( const OfxTime t, const OfxPointD& renderScale ) const
01148 {
01149         OfxRectI rod = getPixelRod( t );
01150         rod.x1 = static_cast<int>( rod.x1 * renderScale.x );
01151         rod.y1 = static_cast<int>( rod.y1 * renderScale.y );
01152         rod.x2 = static_cast<int>( rod.x2 * renderScale.x );
01153         rod.y2 = static_cast<int>( rod.y2 * renderScale.y );
01154         return rod;
01155 }
01156 
01157 /** @brief fetch an image */
01158 Image* Clip::fetchImage( OfxTime t )
01159 {
01160         OfxPropertySetHandle imageHandle;
01161         OfxStatus stat = OFX::Private::gEffectSuite->clipGetImage( _clipHandle, t, NULL, &imageHandle );
01162 
01163         if( stat == kOfxStatFailed )
01164         {
01165         return NULL; // not an error, fetched images out of range/region, assume black and transparent
01166         }
01167         else
01168         throwSuiteStatusException( stat );
01169 
01170         return new Image( imageHandle );
01171 }
01172 
01173 /** @brief fetch an image, with a specific region in cannonical coordinates */
01174 Image* Clip::fetchImage( OfxTime t, OfxRectD bounds )
01175 {
01176         OfxPropertySetHandle imageHandle;
01177         OfxStatus stat = OFX::Private::gEffectSuite->clipGetImage( _clipHandle, t, &bounds, &imageHandle );
01178 
01179         if( stat == kOfxStatFailed )
01180         {
01181         return NULL; // not an error, fetched images out of range/region, assume black and transparent
01182         }
01183         else
01184         throwSuiteStatusException( stat );
01185 
01186         return new Image( imageHandle );
01187 }
01188 
01189 ////////////////////////////////////////////////////////////////////////////////
01190 /// image effect
01191 
01192 /** @brief ctor */
01193 ImageEffect::ImageEffect( OfxImageEffectHandle handle )
01194         : _effectHandle( handle ),
01195         _effectProps( 0 ),
01196         _context( eContextNone ),
01197         _progressStartSuccess( false )
01198 {
01199         // get the property handle
01200         _effectProps = OFX::Private::fetchEffectProps( handle );
01201 
01202         // Set this as the instance data pointer on the effect handle
01203         _effectProps.propSetPointer( kOfxPropInstanceData, this );
01204 
01205         // validate the plugin instance
01206         OFX::Validation::validatePluginInstanceProperties( _effectProps );
01207 
01208         // fetch the context
01209         std::string ctxt = _effectProps.propGetString( kOfxImageEffectPropContext );
01210         _context = mapContextStringToEnum( ctxt );
01211 
01212         // the param set daddy-oh
01213         OfxParamSetHandle paramSet;
01214         OfxStatus stat = OFX::Private::gEffectSuite->getParamSet( handle, &paramSet );
01215         throwSuiteStatusException( stat );
01216         setParamSetHandle( paramSet );
01217 
01218 }
01219 
01220 /** @brief dtor */
01221 ImageEffect::~ImageEffect()
01222 {
01223         // clobber the instance data property on the effect handle
01224         _effectProps.propSetPointer( kOfxPropInstanceData, 0 );
01225 
01226         // delete any clip instances we may have constructed
01227         std::map<std::string, Clip*>::iterator iter;
01228         for( iter = _fetchedClips.begin(); iter != _fetchedClips.end(); ++iter )
01229         {
01230         if( iter->second )
01231         {
01232                 delete iter->second;
01233                 iter->second = NULL;
01234         }
01235         }
01236 }
01237 
01238 /** @brief the context this effect was instantiate in */
01239 EContext ImageEffect::getContext( void ) const
01240 {
01241         //std::cout << "debug... getContext enum:" << (int)_context << " str:" << mapContextEnumToString(_context) << std::endl;
01242         return _context;
01243 }
01244 
01245 /** @brief size of the project */
01246 OfxPointD ImageEffect::getProjectSize( void ) const
01247 {
01248         OfxPointD v;
01249 
01250         v.x = _effectProps.propGetDouble( kOfxImageEffectPropProjectSize, 0 );
01251         v.y = _effectProps.propGetDouble( kOfxImageEffectPropProjectSize, 1 );
01252         return v;
01253 }
01254 
01255 /** @brief origin of the project */
01256 OfxPointD ImageEffect::getProjectOffset( void ) const
01257 {
01258         OfxPointD v;
01259 
01260         v.x = _effectProps.propGetDouble( kOfxImageEffectPropProjectOffset, 0 );
01261         v.y = _effectProps.propGetDouble( kOfxImageEffectPropProjectOffset, 1 );
01262         return v;
01263 }
01264 
01265 /** @brief extent of the project */
01266 OfxPointD ImageEffect::getProjectExtent( void ) const
01267 {
01268         OfxPointD v;
01269 
01270         v.x = _effectProps.propGetDouble( kOfxImageEffectPropProjectExtent, 0 );
01271         v.y = _effectProps.propGetDouble( kOfxImageEffectPropProjectExtent, 1 );
01272         return v;
01273 }
01274 
01275 /** @brief pixel aspect ratio of the project */
01276 double ImageEffect::getProjectPixelAspectRatio( void ) const
01277 {
01278         return _effectProps.propGetDouble( kOfxImageEffectPropProjectPixelAspectRatio, 0 );
01279 }
01280 
01281 /** @brief how long does the effect last */
01282 double ImageEffect::getEffectDuration( void ) const
01283 {
01284         return _effectProps.propGetDouble( kOfxImageEffectInstancePropEffectDuration, 0 );
01285 }
01286 
01287 /** @brief the frame rate of the project */
01288 double ImageEffect::getFrameRate( void ) const
01289 {
01290         return _effectProps.propGetDouble( kOfxImageEffectPropFrameRate, 0 );
01291 }
01292 
01293 /** @brief is the instance currently being interacted with */
01294 bool ImageEffect::isInteractive( void ) const
01295 {
01296         return _effectProps.propGetInt( kOfxPropIsInteractive ) != 0;
01297 }
01298 
01299 /** @brief set the instance to be sequentially renderred, this should have been part of clip preferences! */
01300 void ImageEffect::setSequentialRender( bool v )
01301 {
01302         _effectProps.propSetInt( kOfxImageEffectInstancePropSequentialRender, int(v) );
01303 }
01304 
01305 /** @brief Have we informed the host we want to be seqentially renderred ? */
01306 bool ImageEffect::getSequentialRender( void ) const
01307 {
01308         return _effectProps.propGetInt( kOfxImageEffectInstancePropSequentialRender ) != 0;
01309 }
01310 
01311 OFX::Message::EMessageReply ImageEffect::sendMessage( OFX::Message::EMessageType type, const std::string& id, const std::string& msg )
01312 {
01313         if( !OFX::Private::gMessageSuite->message )
01314         {
01315         throwHostMissingSuiteException( "message" );
01316         }
01317         OfxStatus stat = OFX::Private::gMessageSuite->message( _effectHandle, mapMessageTypeEnumToString( type ).c_str(), id.c_str(), msg.c_str() );
01318         return mapMessageReplyStatusToEnum( stat );
01319 }
01320 
01321 /** @brief Fetch the named clip from this instance */
01322 Clip* ImageEffect::fetchClip( const std::string& name )
01323 {
01324         // do we have the clip already
01325         std::map<std::string, Clip*>::const_iterator search;
01326         search = _fetchedClips.find( name );
01327         if( search != _fetchedClips.end() )
01328         return search->second;
01329 
01330         // fetch the property set handle of the effect
01331         OfxImageClipHandle clipHandle   = 0;
01332         OfxPropertySetHandle propHandle = 0;
01333         OfxStatus stat                  = OFX::Private::gEffectSuite->clipGetHandle( getHandle(), name.c_str(), &clipHandle, &propHandle );
01334         throwSuiteStatusException( stat );
01335 
01336         // and make one
01337         Clip* newClip = new Clip( this, name, clipHandle, propHandle );
01338 
01339         // add it in
01340         _fetchedClips[name] = newClip;
01341 
01342         // return it
01343         return newClip;
01344 }
01345 
01346 /** @brief Fetch a parametric param */
01347 CameraParam* ImageEffect::fetchCameraParam( const std::string& name )
01348 {
01349         return fetchAttribute<CameraParam>( getHandle(), name );
01350 }
01351 
01352 /** @brief does the host want us to abort rendering? */
01353 bool ImageEffect::abort() const
01354 {
01355         return OFX::Private::gEffectSuite->abort( _effectHandle ) != 0;
01356 }
01357 
01358 /** @brief adds a new interact to the set of interacts open on this effect */
01359 void ImageEffect::addOverlayInteract( OverlayInteract* interact )
01360 {
01361         // do we have it already ?
01362         std::list<OverlayInteract*>::iterator i;
01363         i = std::find( _overlayInteracts.begin(), _overlayInteracts.end(), interact );
01364 
01365         // we don't, put it in there
01366         if( i == _overlayInteracts.end() )
01367         {
01368         // we have a new one to add in here
01369         _overlayInteracts.push_back( interact );
01370         }
01371 }
01372 
01373 /** @brief removes an interact to the set of interacts open on this effect */
01374 void ImageEffect::removeOverlayInteract( OverlayInteract* interact )
01375 {
01376         // find it
01377         std::list<OverlayInteract*>::iterator i;
01378         i = std::find( _overlayInteracts.begin(), _overlayInteracts.end(), interact );
01379 
01380         // and remove it
01381         if( i != _overlayInteracts.end() )
01382         {
01383         _overlayInteracts.erase( i );
01384         }
01385 }
01386 
01387 /** @brief force all overlays on this interact to be redrawn */
01388 void ImageEffect::redrawOverlays( void )
01389 {
01390         // find it
01391         std::list<OverlayInteract*>::iterator i;
01392         for( i = _overlayInteracts.begin(); i != _overlayInteracts.end(); ++i )
01393         {
01394         ( *i )->requestRedraw();
01395         }
01396 }
01397 
01398 ////////////////////////////////////////////////////////////////////////////////
01399 // below are the default members for the base image effect
01400 
01401 /** @brief client is identity function, returns the clip and time for the identity function
01402 */
01403 bool ImageEffect::isIdentity( const RenderArguments& args, Clip*& identityClip, double& identityTime )
01404 {
01405         return false; // by default, we are not an identity operation
01406 }
01407 
01408 /** @brief The get RoD action */
01409 bool ImageEffect::getRegionOfDefinition( const RegionOfDefinitionArguments& args, OfxRectD& rod )
01410 {
01411         return false; // by default, we are not setting the RoD
01412 }
01413 
01414 /** @brief the get RoI action */
01415 void ImageEffect::getRegionsOfInterest( const RegionsOfInterestArguments& args, RegionOfInterestSetter& rois )
01416 {
01417         // fa niente
01418 }
01419 
01420 /** @brief the get frames needed action */
01421 void ImageEffect::getFramesNeeded( const FramesNeededArguments& args, FramesNeededSetter& frames )
01422 {
01423         // fa niente
01424 }
01425 
01426 /** @brief client begin sequence render function */
01427 void ImageEffect::beginSequenceRender( const BeginSequenceRenderArguments& args )
01428 {
01429         // fa niente
01430 }
01431 
01432 /** @brief client end sequence render function, this is one of the few that must be set */
01433 void ImageEffect::endSequenceRender( const EndSequenceRenderArguments& args )
01434 {
01435         // fa niente
01436 }
01437 
01438 /** @brief The purge caches action, a request for an instance to free up as much memory as possible in low memory situations */
01439 void ImageEffect::purgeCaches( void )
01440 {
01441         // fa niente
01442 }
01443 
01444 /** @brief The sync private data action, called when the effect needs to sync any private data to persistant parameters */
01445 void ImageEffect::syncPrivateData( void )
01446 {
01447         // fa niente
01448 }
01449 
01450 /** @brief get the clip preferences */
01451 void ImageEffect::getClipPreferences( ClipPreferencesSetter& clipPreferences )
01452 {
01453         // fa niente
01454 }
01455 
01456 /** @brief the effect is about to be actively edited by a user, called when the first user interface is opened on an instance */
01457 void ImageEffect::beginEdit( void )
01458 {
01459         // fa niente
01460 }
01461 
01462 /** @brief the effect is no longer being edited by a user, called when the last user interface is closed on an instance */
01463 void ImageEffect::endEdit( void )
01464 {
01465         // fa niente
01466 }
01467 
01468 /** @brief the effect is about to have some values changed */
01469 void ImageEffect::beginChanged( InstanceChangeReason reason )
01470 {}
01471 
01472 /** @brief called when a param has just had its value changed */
01473 void ImageEffect::changedParam( const InstanceChangedArgs& args, const std::string& paramName )
01474 {}
01475 
01476 /** @brief called when a clip has just been changed in some way (a rewire maybe) */
01477 void ImageEffect::changedClip( const InstanceChangedArgs& args, const std::string& clipName )
01478 {}
01479 
01480 /** @brief the effect has just had some values changed */
01481 void ImageEffect::endChanged( InstanceChangeReason reason )
01482 {}
01483 
01484 /** @brief get the time domain */
01485 bool ImageEffect::getTimeDomain( OfxRangeD& range )
01486 {
01487         // by default, do the default
01488         return false;
01489 }
01490 
01491 /// Start doing progress.
01492 void ImageEffect::progressStart( const std::string& message )
01493 {
01494         if( OFX::Private::gProgressSuite )
01495         {
01496         OfxStatus stat = OFX::Private::gProgressSuite->progressStart( (void*) _effectHandle, message.c_str() );
01497         _progressStartSuccess = ( stat == kOfxStatOK );
01498         }
01499 }
01500 
01501 /// finish yer progress
01502 void ImageEffect::progressEnd()
01503 {
01504         if( OFX::Private::gProgressSuite && _progressStartSuccess )
01505         {
01506         OFX::Private::gProgressSuite->progressEnd( (void*) _effectHandle );
01507         }
01508 }
01509 
01510 /// set the progress to some level of completion,
01511 /// returns true if you should abandon processing, false to continue
01512 bool ImageEffect::progressUpdate( const double t )
01513 {
01514         if( OFX::Private::gProgressSuite && _progressStartSuccess )
01515         {
01516         const OfxStatus stat = OFX::Private::gProgressSuite->progressUpdate( (void*) _effectHandle, t );
01517         if( stat == kOfxStatReplyNo )
01518                 return true;
01519         }
01520         return false;
01521 }
01522 
01523 /// get the current time on the timeline. This is not necessarily the same
01524 /// time as being passed to an action (eg render)
01525 double ImageEffect::timeLineGetTime()
01526 {
01527         if( OFX::Private::gTimeLineSuite )
01528         {
01529         double time;
01530         if( OFX::Private::gTimeLineSuite->getTime( (void*) _effectHandle, &time ) == kOfxStatOK )
01531                 return time;
01532         }
01533         return 0;
01534 }
01535 
01536 /// set the timeline to a specific time
01537 void ImageEffect::timeLineGotoTime( const double t )
01538 {
01539         if( OFX::Private::gTimeLineSuite )
01540         {
01541         OFX::Private::gTimeLineSuite->gotoTime( (void*) _effectHandle, t );
01542         }
01543 }
01544 
01545 /// get the first and last times available on the effect's timeline
01546 void ImageEffect:: timeLineGetBounds( double& t1, double& t2 )
01547 {
01548         t1 = t2 = 0;
01549         if( OFX::Private::gTimeLineSuite )
01550         {
01551         OFX::Private::gTimeLineSuite->getTimeBounds( (void*) _effectHandle, &t1, &t2 );
01552         }
01553 }
01554 
01555 ////////////////////////////////////////////////////////////////////////////////
01556 // Class used to set the clip preferences of the effect. */
01557 
01558 const std::string& ClipPreferencesSetter::extractValueForName( const StringStringMap& m, const std::string& name )
01559 {
01560         StringStringMap::const_iterator it = m.find( name );
01561 
01562         if( it == m.end() )
01563         BOOST_THROW_EXCEPTION( Exception::PropertyUnknownToHost( name ) );
01564         return it->second;
01565 }
01566 
01567 /** @brief, force the host to set a clip's mapped component type to be \em comps.  */
01568 void ClipPreferencesSetter::setClipComponents( Clip& clip, EPixelComponent comps )
01569 {
01570         doneSomething_ = true;
01571         const std::string& propName = extractValueForName( clipComponentPropNames_, clip.name() );
01572 
01573         switch( comps )
01574         {
01575         case ePixelComponentRGBA:
01576                 outArgs_.propSetString( propName.c_str(), kOfxImageComponentRGBA );
01577                 break;
01578         case ePixelComponentRGB:
01579                 outArgs_.propSetString( propName.c_str(), kOfxImageComponentRGB );
01580                 break;
01581         case ePixelComponentAlpha:
01582                 outArgs_.propSetString( propName.c_str(), kOfxImageComponentAlpha );
01583                 break;
01584         case ePixelComponentCustom:
01585                 break;
01586         case ePixelComponentNone:
01587                 outArgs_.propSetString( propName.c_str(), kOfxImageComponentNone );
01588                 break;
01589         }
01590 }
01591 
01592 /** @brief, force the host to set a clip's mapped bit depth be \em bitDepth */
01593 void ClipPreferencesSetter::setClipBitDepth( Clip& clip, EBitDepth bitDepth )
01594 {
01595         doneSomething_ = true;
01596         const std::string& propName = extractValueForName( clipDepthPropNames_, clip.name() );
01597 
01598         if( _imageEffectHostDescription->supportsMultipleClipDepths )
01599         {
01600         switch( bitDepth )
01601         {
01602                 case eBitDepthUByte:
01603                 outArgs_.propSetString( propName.c_str(), kOfxBitDepthByte );
01604                 break;
01605                 case eBitDepthUShort:
01606                 outArgs_.propSetString( propName.c_str(), kOfxBitDepthShort );
01607                 break;
01608                 case eBitDepthFloat:
01609                 outArgs_.propSetString( propName.c_str(), kOfxBitDepthFloat );
01610                 break;
01611                 case eBitDepthNone:
01612                 outArgs_.propSetString( propName.c_str(), kOfxBitDepthNone );
01613                 break;
01614                 case eBitDepthCustom:
01615                 // what the good way ?
01616                 break;
01617         }
01618         }
01619         else
01620         {
01621         // BOOST_THROW_EXCEPTION( std::logic_error("Host doesn't support multiple bit depths.") );
01622         // it's not clear what we need to to in this case...
01623         // set the value supported by the host or set nothing
01624         // by setting this value, we may have less problem depending on host implementations
01625         outArgs_.propSetString( propName.c_str(), mapBitDepthEnumToString( _imageEffectHostDescription->getPixelDepth() ) );
01626         }
01627 }
01628 
01629 /** @brief, force the host to set a clip's mapped Pixel Aspect Ratio to be \em PAR */
01630 void ClipPreferencesSetter::setPixelAspectRatio( Clip& clip, double PAR )
01631 {
01632         if( ! _imageEffectHostDescription->supportsMultipleClipPARs )
01633         return;
01634 //              BOOST_THROW_EXCEPTION( std::logic_error("Host doesn't support multiple Pixel Aspect Ratios.") );
01635 
01636         doneSomething_ = true;
01637         const std::string& propName = extractValueForName( clipPARPropNames_, clip.name() );
01638         outArgs_.propSetDouble( propName.c_str(), PAR );
01639 }
01640 
01641 /** @brief Allows an effect to change the output frame rate */
01642 void ClipPreferencesSetter::setOutputFrameRate( double v )
01643 {
01644         if( ! _imageEffectHostDescription->supportsSetableFrameRate )
01645         return;
01646 //              BOOST_THROW_EXCEPTION( std::logic_error("Host doesn't support setable frame rate.") );
01647 
01648         doneSomething_ = true;
01649         outArgs_.propSetDouble( kOfxImageEffectPropFrameRate, v );
01650 }
01651 
01652 /** @brief Set the premultiplication state of the output clip. */
01653 void ClipPreferencesSetter::setOutputPremultiplication( EPreMultiplication v )
01654 {
01655         doneSomething_ = true;
01656         switch( v )
01657         {
01658         case eImageOpaque:
01659                 outArgs_.propSetString( kOfxImageEffectPropPreMultiplication, kOfxImageOpaque );
01660                 break;
01661         case eImagePreMultiplied:
01662                 outArgs_.propSetString( kOfxImageEffectPropPreMultiplication, kOfxImagePreMultiplied );
01663                 break;
01664         case eImageUnPreMultiplied:
01665                 outArgs_.propSetString( kOfxImageEffectPropPreMultiplication, kOfxImageUnPreMultiplied );
01666                 break;
01667         }
01668 }
01669 
01670 /** @brief Set whether the effect can be continously sampled. */
01671 void ClipPreferencesSetter::setOutputHasContinousSamples( bool v )
01672 {
01673         doneSomething_ = true;
01674         outArgs_.propSetInt( kOfxImageClipPropContinuousSamples, int(v) );
01675 }
01676 
01677 /** @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). */
01678 void ClipPreferencesSetter::setOutputFrameVarying( bool v )
01679 {
01680         doneSomething_ = true;
01681         outArgs_.propSetInt( kOfxImageEffectFrameVarying, int(v) );
01682 }
01683 
01684 void ClipPreferencesSetter::setOutputFielding( EField v )
01685 {
01686         doneSomething_ = true;
01687         switch( v )
01688         {
01689         case eFieldNone: outArgs_.propSetString( kOfxImageClipPropFieldOrder, kOfxImageFieldNone, 0, false ); break;
01690         case eFieldLower: outArgs_.propSetString( kOfxImageClipPropFieldOrder, kOfxImageFieldLower, 0, false ); break;
01691         case eFieldUpper: outArgs_.propSetString( kOfxImageClipPropFieldOrder, kOfxImageFieldUpper, 0, false ); break;
01692         case eFieldBoth: outArgs_.propSetString( kOfxImageClipPropFieldOrder, kOfxImageFieldBoth, 0, false ); break;
01693                 // kOfxImageFieldSingle ?
01694                 // kOfxImageFieldDoubled ?
01695         }
01696 }
01697 
01698 ////////////////////////////////////////////////////////////////////////////////
01699 /** @brief Class that skins image memory allocation */
01700 
01701 ImageMemory::ImageMemory()
01702         : _handle( 0 )
01703         , _alloc(false)
01704 {
01705 }
01706 
01707 ImageMemory::ImageMemory( size_t nBytes, ImageEffect* associatedEffect )
01708         : _handle( 0 )
01709         , _alloc(false)
01710 {
01711         alloc( nBytes, associatedEffect );
01712 }
01713 
01714 /** @brief dtor */
01715 ImageMemory::~ImageMemory()
01716 {
01717         if( _alloc )
01718         {
01719                 /*OfxStatus stat = */ OFX::Private::gEffectSuite->imageMemoryFree( _handle );
01720         }
01721         // ignore status code for exception purposes
01722 }
01723 
01724 void ImageMemory::alloc( size_t nBytes, ImageEffect* associatedEffect )
01725 {
01726         BOOST_ASSERT( ! _alloc );
01727         _alloc = true;
01728         OfxImageEffectHandle effectHandle = 0;
01729 
01730         if( associatedEffect != 0 )
01731         {
01732                 effectHandle = associatedEffect->_effectHandle;
01733         }
01734 
01735         OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryAlloc( effectHandle, nBytes, &_handle );
01736         if( stat == kOfxStatErrMemory )
01737                 BOOST_THROW_EXCEPTION( std::bad_alloc() );
01738         throwSuiteStatusException( stat );
01739 }
01740 
01741 /** @brief lock the memory and return a pointer to it */
01742 void* ImageMemory::lock( void )
01743 {
01744         void* ptr;
01745         OfxStatus stat = OFX::Private::gEffectSuite->imageMemoryLock( _handle, &ptr );
01746 
01747         if( stat == kOfxStatErrMemory )
01748         BOOST_THROW_EXCEPTION( std::bad_alloc() );
01749         throwSuiteStatusException( stat );
01750         return ptr;
01751 }
01752 
01753 /** @brief unlock the memory */
01754 void ImageMemory::unlock( void )
01755 {
01756         /*OfxStatus stat = */ OFX::Private::gEffectSuite->imageMemoryUnlock( _handle );
01757 }
01758 
01759 /** @brief OFX::Private namespace, for things private to the support library code here generally calls image effect class members */
01760 namespace Private {
01761 
01762 /** @brief Creates the global host description and sets its properties */
01763 void fetchHostDescription( OfxHost* host )
01764 {
01765         OFX::Log::error( OFX::Private::gHostDescriptionHasInit, "Tried to create host description when we already have one." );
01766         if( !OFX::Private::gHostDescriptionHasInit )
01767         {
01768         OFX::Private::gHostDescriptionHasInit = true;
01769         // wrap the property handle up with a property set
01770         PropertySet hostProps( host->host );
01771 
01772         // and get some properties
01773         gHostDescription.hostName                    = hostProps.propGetString( kOfxPropName );
01774         gHostDescription.hostLabel                   = hostProps.propGetString( kOfxPropLabel );
01775         gHostDescription.hostIsBackground            = hostProps.propGetInt( kOfxImageEffectHostPropIsBackground ) != 0;
01776         gHostDescription.supportsOverlays            = hostProps.propGetInt( kOfxImageEffectPropSupportsOverlays ) != 0;
01777         gHostDescription.supportsMultiResolution     = hostProps.propGetInt( kOfxImageEffectPropSupportsMultiResolution ) != 0;
01778         gHostDescription.supportsTiles               = hostProps.propGetInt( kOfxImageEffectPropSupportsTiles ) != 0;
01779         gHostDescription.temporalClipAccess          = hostProps.propGetInt( kOfxImageEffectPropTemporalClipAccess ) != 0;
01780         gHostDescription.supportsMultipleClipDepths  = hostProps.propGetInt( kOfxImageEffectPropSupportsMultipleClipDepths ) != 0;
01781         gHostDescription.supportsMultipleClipPARs    = hostProps.propGetInt( kOfxImageEffectPropSupportsMultipleClipPARs ) != 0;
01782         gHostDescription.supportsSetableFrameRate    = hostProps.propGetInt( kOfxImageEffectPropSetableFrameRate ) != 0;
01783         gHostDescription.supportsSetableFielding     = hostProps.propGetInt( kOfxImageEffectPropSetableFielding ) != 0;
01784         gHostDescription.supportsStringAnimation     = hostProps.propGetInt( kOfxParamHostPropSupportsStringAnimation ) != 0;
01785         gHostDescription.supportsCustomInteract      = hostProps.propGetInt( kOfxParamHostPropSupportsCustomInteract ) != 0;
01786         gHostDescription.supportsChoiceAnimation     = hostProps.propGetInt( kOfxParamHostPropSupportsChoiceAnimation ) != 0;
01787         gHostDescription.supportsBooleanAnimation    = hostProps.propGetInt( kOfxParamHostPropSupportsBooleanAnimation ) != 0;
01788         gHostDescription.supportsCustomAnimation     = hostProps.propGetInt( kOfxParamHostPropSupportsCustomAnimation ) != 0;
01789         gHostDescription.supportsParametricParameter = gParametricParameterSuite != NULL;
01790         gHostDescription.supportsCameraParameter     = gCameraParameterSuite != NULL;
01791         gHostDescription.maxParameters               = hostProps.propGetInt( kOfxParamHostPropMaxParameters );
01792         gHostDescription.maxPages                    = hostProps.propGetInt( kOfxParamHostPropMaxPages );
01793         gHostDescription.pageRowCount                = hostProps.propGetInt( kOfxParamHostPropPageRowColumnCount, 0 );
01794         gHostDescription.pageColumnCount             = hostProps.propGetInt( kOfxParamHostPropPageRowColumnCount, 1 );
01795         int numComponents = hostProps.propGetDimension( kOfxImageEffectPropSupportedComponents );
01796         for( int i = 0; i < numComponents; ++i )
01797                 gHostDescription._supportedComponents.push_back( mapPixelComponentStringToEnum( hostProps.propGetString( kOfxImageEffectPropSupportedComponents, i ) ) );
01798 
01799         int numContexts = hostProps.propGetDimension( kOfxImageEffectPropSupportedContexts );
01800         for( int i = 0; i < numContexts; ++i )
01801                 gHostDescription._supportedContexts.push_back( mapContextStringToEnum( hostProps.propGetString( kOfxImageEffectPropSupportedContexts, i ) ) );
01802 
01803         int numPixelDepths = hostProps.propGetDimension( kOfxImageEffectPropSupportedPixelDepths );
01804         for( int i = 0; i < numPixelDepths; ++i )
01805                 gHostDescription._supportedPixelDepths.push_back( mapBitDepthStringToEnum( hostProps.propGetString( kOfxImageEffectPropSupportedPixelDepths, i ) ) );
01806         }
01807 }
01808 
01809 /** @brief fetch the effect property set from the ImageEffectHandle */
01810 OFX::PropertySet fetchEffectProps( OfxImageEffectHandle handle )
01811 {
01812         // get the property handle
01813         OfxPropertySetHandle propHandle;
01814         OfxStatus stat = OFX::Private::gEffectSuite->getPropertySet( handle, &propHandle );
01815 
01816         throwSuiteStatusException( stat );
01817         return OFX::PropertySet( propHandle );
01818 }
01819 
01820 /** @brief Library side load action, this fetches all the suite pointers */
01821 void loadAction( void )
01822 {
01823         ++Private::gLoadCount;
01824 
01825         //OfxStatus status = kOfxStatOK;
01826 
01827         // fetch the suites
01828         OFX::Log::error( gHost == 0, "Host pointer has not been set." );
01829         if( !gHost )
01830                 BOOST_THROW_EXCEPTION( OFX::Exception::Suite( kOfxStatErrBadHandle ) );
01831 
01832         if( Private::gLoadCount == 1 )
01833         {
01834                 gEffectSuite   = (OfxImageEffectSuiteV1*) fetchSuite( kOfxImageEffectSuite, 1 );
01835                 gPropSuite     = (OfxPropertySuiteV1*)    fetchSuite( kOfxPropertySuite, 1 );
01836                 gParamSuite    = (OfxParameterSuiteV1*)   fetchSuite( kOfxParameterSuite, 1 );
01837                 gMemorySuite   = (OfxMemorySuiteV1*)      fetchSuite( kOfxMemorySuite, 1 );
01838                 gThreadSuite   = (OfxMultiThreadSuiteV1*) fetchSuite( kOfxMultiThreadSuite, 1 );
01839                 gMessageSuite  = (OfxMessageSuiteV1*)     fetchSuite( kOfxMessageSuite, 1 );
01840                 gProgressSuite = (OfxProgressSuiteV1*)     fetchSuite( kOfxProgressSuite, 1, true );
01841                 gTimeLineSuite = (OfxTimeLineSuiteV1*)     fetchSuite( kOfxTimeLineSuite, 1, true );
01842                 gParametricParameterSuite = static_cast<OfxParametricParameterSuiteV1*>( OFX::fetchSuite( kOfxParametricParameterSuite, 1, true ) );
01843                 gCameraParameterSuite = static_cast<NukeOfxCameraSuiteV1*>( OFX::fetchSuite( kNukeOfxCameraSuite, 1, true ) );
01844 
01845                 // OK check and fetch host information
01846                 fetchHostDescription( gHost );
01847 
01848                 /// and set some dendent flags
01849                 OFX::Private::gHostDescription.supportsProgressSuite = ( gProgressSuite != NULL );
01850                 OFX::Private::gHostDescription.supportsTimeLineSuite = ( gTimeLineSuite != NULL );
01851 
01852                 // fetch the interact suite if the host supports interaction
01853                 if( OFX::Private::gHostDescription.supportsOverlays || OFX::Private::gHostDescription.supportsCustomInteract )
01854                         gInteractSuite = (OfxInteractSuiteV1*) fetchSuite( kOfxInteractSuite, 1 );
01855         }
01856 
01857         // initialise the validation code
01858         OFX::Validation::initialise();
01859 
01860         // validate the host
01861         OFX::Validation::validateHostProperties( gHost );
01862 
01863 }
01864 
01865 /** @brief Library side unload action, this fetches all the suite pointers */
01866 void unloadAction( const char* id )
01867 {
01868         --Private::gLoadCount;
01869 
01870     if( Private::gLoadCount < 0 )
01871     {
01872         std::cerr << "OFX Plugin \"" << id << "\" is already unloaded." << std::endl;
01873         return;
01874     }
01875 
01876         {
01877                 EffectDescriptorMap::iterator it = gEffectDescriptors.find( id );
01878                 EffectContextMap& toBeDeleted    = it->second;
01879                 for( EffectContextMap::iterator it2 = toBeDeleted.begin(); it2 != toBeDeleted.end(); ++it2 )
01880                 {
01881                         OFX::ImageEffectDescriptor* desc = it2->second;
01882                         delete desc;
01883                 }
01884                 toBeDeleted.clear();
01885         }
01886         {
01887                 OFX::OfxPlugInfoMap::iterator it  = OFX::Private::plugInfoMap.find( id );
01888                 if( it == OFX::Private::plugInfoMap.end() )
01889                         BOOST_THROW_EXCEPTION( OFX::Exception::Suite( kOfxStatErrBadIndex, std::string("Can't unload the plugin \"") + id + "\".") );
01890                 OfxPlugin* plugin = it->second._plug;
01891                 OFX::OfxPluginArray::iterator it2 = std::find( ofxPlugs.begin(), ofxPlugs.end(), plugin );
01892                 if( it2 == ofxPlugs.end() )
01893                         BOOST_THROW_EXCEPTION( OFX::Exception::Suite( kOfxStatErrBadIndex, std::string("Can't unload the plugin \"") + id + "\".") );
01894                 (*it2) = NULL; // set the plugin as unloaded but keep the index
01895                 delete plugin;
01896                 //it->second._plug = NULL; // delete the plugin but keep an entry into the map
01897         }
01898 
01899         if( Private::gLoadCount == 0 )
01900         {
01901                 // force these to null
01902                 gEffectSuite   = NULL;
01903                 gPropSuite     = NULL;
01904                 gParamSuite    = NULL;
01905                 gMemorySuite   = NULL;
01906                 gThreadSuite   = NULL;
01907                 gMessageSuite  = NULL;
01908                 gInteractSuite = NULL;
01909                 gParametricParameterSuite = NULL;
01910                 gCameraParameterSuite = NULL;
01911 
01912                 ofxPlugs.clear();
01913                 gHasInit = false;
01914         }
01915 }
01916 
01917 /** @brief fetches our pointer out of the props on the handle */
01918 ImageEffect* retrieveImageEffectPointer( OfxImageEffectHandle handle )
01919 {
01920         ImageEffect* instance;
01921 
01922         // get the prop set on the handle
01923         OfxPropertySetHandle propHandle;
01924         OfxStatus stat = OFX::Private::gEffectSuite->getPropertySet( handle, &propHandle );
01925 
01926         throwSuiteStatusException( stat );
01927 
01928         // make our wrapper object
01929         PropertySet props( propHandle );
01930 
01931         // fetch the instance data out of the properties
01932         instance = (ImageEffect*) props.propGetPointer( kOfxPropInstanceData );
01933 
01934         OFX::Log::error( instance == NULL, "Instance data handle in effect instance properties is NULL!" );
01935 
01936         if( instance == NULL )
01937         {
01938         BOOST_THROW_EXCEPTION( OFX::Exception::Suite( kOfxStatErrBadHandle, std::string("Can't retrieve ImageEffect pointer from ofxImageEffectHandle. (property: ") + kOfxPropInstanceData + " is NULL).\nThe plugin will crash...") );
01939         }
01940         // and dance to the music
01941         return instance;
01942 }
01943 
01944 /** @brief Checks the handles passed into the plugin's main entry point */
01945 void checkMainHandles( const std::string& action,  const void* handle,
01946                         OfxPropertySetHandle inArgsHandle,  OfxPropertySetHandle outArgsHandle,
01947                         bool handleCanBeNull, bool inArgsCanBeNull, bool outArgsCanBeNull )
01948 {
01949         if( handleCanBeNull )
01950                 OFX::Log::warning( handle != 0, "Handle passed to '%s' is not null.", action.c_str() );
01951         else
01952                 OFX::Log::error( handle == 0, "'Handle passed to '%s' is null.", action.c_str() );
01953 
01954         if( inArgsCanBeNull )
01955                 OFX::Log::warning( inArgsHandle != 0, "'inArgs' Handle passed to '%s' is not null.", action.c_str() );
01956         else
01957                 OFX::Log::error( inArgsHandle == 0, "'inArgs' handle passed to '%s' is null.", action.c_str() );
01958 
01959         if( outArgsCanBeNull )
01960                 OFX::Log::warning( outArgsHandle != 0, "'outArgs' Handle passed to '%s' is not null.", action.c_str() );
01961         else
01962                 OFX::Log::error( outArgsHandle == 0, "'outArgs' handle passed to '%s' is null.", action.c_str() );
01963 
01964         // validate the property sets on the arguments
01965         OFX::Validation::validateActionArgumentsProperties( action, inArgsHandle, outArgsHandle );
01966 
01967         // throw exceptions if null when not meant to be null
01968         if( !handleCanBeNull && !handle )
01969                 throwSuiteStatusException( kOfxStatErrBadHandle );
01970         if( !inArgsCanBeNull && !inArgsHandle )
01971                 throwSuiteStatusException( kOfxStatErrBadHandle );
01972         if( !outArgsCanBeNull && !outArgsHandle )
01973                 throwSuiteStatusException( kOfxStatErrBadHandle );
01974 }
01975 
01976 /** @brief Fetches the arguments used in a render action 'inargs' property set into a POD struct */
01977 void getRenderActionArguments( RenderArguments& args,  OFX::PropertySet inArgs )
01978 {
01979         args.time = inArgs.propGetDouble( kOfxPropTime );
01980 
01981         args.renderScale.x = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 0 );
01982         args.renderScale.y = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 1 );
01983 
01984         args.renderWindow.x1 = inArgs.propGetInt( kOfxImageEffectPropRenderWindow, 0 );
01985         args.renderWindow.y1 = inArgs.propGetInt( kOfxImageEffectPropRenderWindow, 1 );
01986         args.renderWindow.x2 = inArgs.propGetInt( kOfxImageEffectPropRenderWindow, 2 );
01987         args.renderWindow.y2 = inArgs.propGetInt( kOfxImageEffectPropRenderWindow, 3 );
01988 
01989         std::string str = inArgs.propGetString( kOfxImageEffectPropFieldToRender );
01990         try
01991         {
01992                 args.fieldToRender = mapFieldStringToEnum( str );
01993         }
01994         catch( std::invalid_argument )
01995         {
01996                 // dud field?
01997                 OFX::Log::error( true, "Unknown field to render '%s'", str.c_str() );
01998 
01999                 // HACK need to throw something to cause a failure
02000         }
02001 }
02002 
02003 /** @brief Library side render action, fetches relevant properties and calls the client code */
02004 void renderAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs )
02005 {
02006         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02007         RenderArguments args;
02008 
02009         // get the arguments
02010         getRenderActionArguments( args, inArgs );
02011 
02012         // and call the plugin client render code
02013         effectInstance->render( args );
02014 }
02015 
02016 /** @brief Library side render begin sequence render action, fetches relevant properties and calls the client code */
02017 void beginSequenceRenderAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs )
02018 {
02019         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02020 
02021         BeginSequenceRenderArguments args;
02022 
02023         args.frameRange.min = inArgs.propGetDouble( kOfxImageEffectPropFrameRange, 0 );
02024         args.frameRange.max = inArgs.propGetDouble( kOfxImageEffectPropFrameRange, 1 );
02025 
02026         args.frameStep = inArgs.propGetDouble( kOfxImageEffectPropFrameStep, 0 );
02027 
02028         args.renderScale.x = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 0 );
02029         args.renderScale.y = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 1 );
02030 
02031         args.isInteractive = inArgs.propGetInt( kOfxPropIsInteractive ) != 0;
02032 
02033         // and call the plugin client render code
02034         effectInstance->beginSequenceRender( args );
02035 }
02036 
02037 /** @brief Library side render begin sequence render action, fetches relevant properties and calls the client code */
02038 void endSequenceRenderAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs )
02039 {
02040         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02041 
02042         EndSequenceRenderArguments args;
02043 
02044         args.renderScale.x = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 0 );
02045         args.renderScale.y = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 1 );
02046 
02047         args.isInteractive = inArgs.propGetInt( kOfxPropIsInteractive ) != 0;
02048 
02049         // and call the plugin client render code
02050         effectInstance->endSequenceRender( args );
02051 }
02052 
02053 /** @brief Library side render begin sequence render action, fetches relevant properties and calls the client code */
02054 bool isIdentityAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet& outArgs )
02055 {
02056         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02057         RenderArguments args;
02058 
02059         // get the arguments
02060         getRenderActionArguments( args, inArgs );
02061 
02062         // and call the plugin client isIdentity code
02063         Clip* identityClip  = 0;
02064         double identityTime = args.time;
02065         bool v              = effectInstance->isIdentity( args, identityClip, identityTime );
02066 
02067         if( v && identityClip )
02068         {
02069         outArgs.propSetString( kOfxPropName, identityClip->name() );
02070         outArgs.propSetDouble( kOfxPropTime, identityTime );
02071         return true;
02072         }
02073         return false;
02074 }
02075 
02076 /** @brief Library side get region of definition function */
02077 bool regionOfDefinitionAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet& outArgs )
02078 {
02079         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02080         RegionOfDefinitionArguments args;
02081 
02082         args.renderScale.x = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 0 );
02083         args.renderScale.y = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 1 );
02084 
02085         args.time = inArgs.propGetDouble( kOfxPropTime );
02086 
02087         // and call the plugin client code
02088         OfxRectD rod;
02089         rod.x1 = outArgs.propGetDouble(kOfxImageEffectPropRegionOfDefinition, 0);
02090         rod.y1 = outArgs.propGetDouble(kOfxImageEffectPropRegionOfDefinition, 1);
02091         rod.x2 = outArgs.propGetDouble(kOfxImageEffectPropRegionOfDefinition, 2);
02092         rod.y2 = outArgs.propGetDouble(kOfxImageEffectPropRegionOfDefinition, 3);
02093         bool v = effectInstance->getRegionOfDefinition( args, rod );
02094 
02095         if( v )
02096         {
02097         outArgs.propSetDouble( kOfxImageEffectPropRegionOfDefinition, rod.x1, 0 );
02098         outArgs.propSetDouble( kOfxImageEffectPropRegionOfDefinition, rod.y1, 1 );
02099         outArgs.propSetDouble( kOfxImageEffectPropRegionOfDefinition, rod.x2, 2 );
02100         outArgs.propSetDouble( kOfxImageEffectPropRegionOfDefinition, rod.y2, 3 );
02101         return true;
02102         }
02103         return false;
02104 }
02105 
02106 /** @brief Library side get regions of interest function */
02107 bool regionsOfInterestAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet& outArgs, const char* plugname )
02108 {
02109         /** @brief local class to set the roi of a clip */
02110         class ActualROISetter : public OFX::RegionOfInterestSetter
02111         {
02112         bool doneSomething_;
02113         OFX::PropertySet& outArgs_;
02114         const std::map<std::string, std::string>& clipROIPropNames_;
02115         const char* _plugname;
02116 
02117         public:
02118         /** @brief ctor */
02119         ActualROISetter( OFX::PropertySet& args, const std::map<std::string, std::string>& clipROIPropNames )
02120                 : doneSomething_( false ),
02121                 outArgs_( args ),
02122                 clipROIPropNames_( clipROIPropNames )
02123         {}
02124 
02125         /** @brief did we set something ? */
02126         bool didSomething( void ) const { return doneSomething_; }
02127 
02128         /** @brief set the RoI of the clip */
02129         virtual void setRegionOfInterest( const Clip& clip, const OfxRectD& roi )
02130         {
02131                 std::map<std::string, std::string>::const_iterator it = clipROIPropNames_.find( clip.name() );
02132                 if( it == clipROIPropNames_.end() )
02133                 BOOST_THROW_EXCEPTION( Exception::PropertyUnknownToHost( clip.name() ) );
02134 
02135                 // construct the name of the property
02136                 const std::string& propName = it->second;
02137 
02138                 // and set it
02139                 outArgs_.propSetDouble( propName.c_str(), roi.x1, 0 );
02140                 outArgs_.propSetDouble( propName.c_str(), roi.y1, 1 );
02141                 outArgs_.propSetDouble( propName.c_str(), roi.x2, 2 );
02142                 outArgs_.propSetDouble( propName.c_str(), roi.y2, 3 );
02143 
02144                 // and record the face we have done something
02145                 doneSomething_ = true;
02146         }
02147 
02148         }; // end of local class
02149 
02150         // fetch our effect pointer
02151         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02152         RegionsOfInterestArguments args;
02153 
02154         // fetch in arguments from the prop handle
02155         args.renderScale.x = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 0 );
02156         args.renderScale.y = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 1 );
02157 
02158         args.regionOfInterest.x1 = inArgs.propGetDouble( kOfxImageEffectPropRegionOfInterest, 0 );
02159         args.regionOfInterest.y1 = inArgs.propGetDouble( kOfxImageEffectPropRegionOfInterest, 1 );
02160         args.regionOfInterest.x2 = inArgs.propGetDouble( kOfxImageEffectPropRegionOfInterest, 2 );
02161         args.regionOfInterest.y2 = inArgs.propGetDouble( kOfxImageEffectPropRegionOfInterest, 3 );
02162 
02163         args.time = inArgs.propGetDouble( kOfxPropTime );
02164 
02165         // make a roi setter object
02166         ActualROISetter setRoIs( outArgs, gEffectDescriptors[plugname][effectInstance->getContext()]->getClipROIPropNames() );
02167 
02168         // and call the plugin client code
02169         effectInstance->getRegionsOfInterest( args, setRoIs );
02170 
02171         // did we do anything ?
02172         if( setRoIs.didSomething() )
02173         return true;
02174         return false;
02175 }
02176 
02177 /** @brief Library side frames needed action */
02178 bool framesNeededAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs, OFX::PropertySet& outArgs, const char* plugname )
02179 {
02180         /** @brief local class to set the frames needed from a clip */
02181         class ActualSetter : public OFX::FramesNeededSetter
02182         {
02183         OFX::PropertySet& outArgs_;                                  /**< @brief property set to set values in */
02184         std::map<std::string, std::vector<OfxRangeD> > frameRanges_;  /**< @brief map holding a bunch of frame ranges, one for each clip */
02185         const std::map<std::string, std::string>& _clipFrameRangePropNames;
02186 
02187         public:
02188         /** @brief ctor */
02189         ActualSetter( OFX::PropertySet& args, const std::map<std::string, std::string>& clipFrameRangePropNames )
02190                 : outArgs_( args ),
02191                 _clipFrameRangePropNames( clipFrameRangePropNames )
02192         {}
02193 
02194         /** @brief set the RoI of the clip */
02195         virtual void setFramesNeeded( const Clip& clip, const OfxRangeD& range )
02196         {
02197                 // insert this into the vector which is in the map
02198                 frameRanges_[clip.name()].push_back( range );
02199         }
02200 
02201         /** @brief write frameRanges_ back to the property set */
02202         bool setOutProperties( void )
02203         {
02204                 bool didSomething = false;
02205 
02206                 std::map<std::string, std::vector<OfxRangeD> >::iterator i;
02207 
02208                 for( i = frameRanges_.begin(); i != frameRanges_.end(); ++i )
02209                 {
02210                 if( i->first != kOfxImageEffectOutputClipName )
02211                 {
02212                         didSomething = true;
02213 
02214                         // Make the property name we are setting
02215                         const std::map<std::string, std::string>::const_iterator it = _clipFrameRangePropNames.find( i->first );
02216                         if( it == _clipFrameRangePropNames.end() )
02217                         BOOST_THROW_EXCEPTION( Exception::PropertyUnknownToHost( i->first ) );
02218 
02219                         const std::string& propName = it->second;
02220 
02221                         // fetch the list of frame ranges
02222                         std::vector<OfxRangeD>& clipRange = i->second;
02223                         std::vector<OfxRangeD>::iterator j;
02224                         int n = 0;
02225 
02226                         // and set 'em
02227                         for( j = clipRange.begin(); j < clipRange.end(); ++j )
02228                         {
02229                         outArgs_.propSetDouble( propName.c_str(), j->min, n++ );
02230                         outArgs_.propSetDouble( propName.c_str(), j->max, n++ );
02231                         }
02232                 }
02233                 }
02234 
02235                 return didSomething;
02236         }
02237 
02238         }; // end of local class
02239 
02240         // fetch our effect pointer
02241         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02242         FramesNeededArguments args;
02243 
02244         // fetch in arguments from the prop handle
02245         args.time = inArgs.propGetDouble( kOfxPropTime );
02246 
02247         // make a roi setter object
02248         ActualSetter setFrames( outArgs, gEffectDescriptors[plugname][effectInstance->getContext()]->getClipFrameRangePropNames() );
02249 
02250         // and call the plugin client code
02251         effectInstance->getFramesNeeded( args, setFrames );
02252 
02253         // Write it back to the properties and see if we set anything
02254         if( setFrames.setOutProperties() )
02255         return true;
02256         return false;
02257 }
02258 
02259 /** @brief Library side get regions of interest function */
02260 bool getTimeDomainAction( OfxImageEffectHandle handle, OFX::PropertySet& outArgs )
02261 {
02262         // fetch our effect pointer
02263         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02264 
02265         // we can only be a general context effect, so check that this is true
02266         OFX::Log::error(
02267                 effectInstance->getContext() != eContextGeneral &&
02268                 effectInstance->getContext() != eContextReader &&
02269                 effectInstance->getContext() != eContextGenerator
02270                 ,
02271                 "Calling kOfxImageEffectActionGetTimeDomain on an effect that is not a 'general', 'reader' or 'generator' context node." );
02272 
02273         OfxRangeD timeDomain;
02274         timeDomain.min = outArgs.propGetDouble( kOfxImageEffectPropFrameRange, 0 );
02275         timeDomain.max = outArgs.propGetDouble( kOfxImageEffectPropFrameRange, 1 );
02276 
02277         // and call the plugin client code
02278         bool v = effectInstance->getTimeDomain( timeDomain );
02279 
02280         if( v )
02281         {
02282         outArgs.propSetDouble( kOfxImageEffectPropFrameRange, timeDomain.min, 0 );
02283         outArgs.propSetDouble( kOfxImageEffectPropFrameRange, timeDomain.max, 1 );
02284         }
02285 
02286         return v;
02287 }
02288 
02289 /** @brief Library side get regions of interest function */
02290 bool clipPreferencesAction( OfxImageEffectHandle handle, OFX::PropertySet& outArgs, const char* plugname )
02291 {
02292         // fetch our effect pointer
02293         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02294 
02295         // set up our clip preferences setter
02296         ImageEffectDescriptor* desc = gEffectDescriptors[plugname][effectInstance->getContext()];
02297         ClipPreferencesSetter prefs( outArgs, desc->getClipDepthPropNames(), desc->getClipComponentPropNames(), desc->getClipPARPropNames() );
02298 
02299         // and call the plug-in client code
02300         effectInstance->getClipPreferences( prefs );
02301 
02302         // did we do anything ?
02303         if( prefs.didSomething() )
02304         return true;
02305         return false;
02306 }
02307 
02308 /** @brief Library side begin instance changed action */
02309 void beginInstanceChangedAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs )
02310 {
02311         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02312 
02313         std::string reasonStr       = inArgs.propGetString( kOfxPropChangeReason );
02314         InstanceChangeReason reason = mapInstanceChangedReasonStringToEnum( reasonStr );
02315 
02316         // and call the plugin client code
02317         effectInstance->beginChanged( reason );
02318 }
02319 
02320 /** @brief Library side instance changed action */
02321 void instanceChangedAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs )
02322 {
02323         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02324 
02325         InstanceChangedArgs args;
02326 
02327         // why did it change
02328         std::string reasonStr = inArgs.propGetString( kOfxPropChangeReason );
02329 
02330         args.reason        = mapInstanceChangedReasonStringToEnum( reasonStr );
02331         args.time          = inArgs.propGetDouble( kOfxPropTime );
02332         args.renderScale.x = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 0 );
02333         args.renderScale.y = inArgs.propGetDouble( kOfxImageEffectPropRenderScale, 1 );
02334 
02335         // what changed
02336         std::string changedType = inArgs.propGetString( kOfxPropType );
02337         std::string changedName = inArgs.propGetString( kOfxPropName );
02338 
02339         if( changedType == kOfxTypeParameter )
02340         {
02341         // and call the plugin client code
02342         effectInstance->changedParam( args, changedName );
02343         }
02344         else if( changedType == kOfxTypeClip )
02345         {
02346         // and call the plugin client code
02347         effectInstance->changedClip( args, changedName );
02348         }
02349         else
02350         {
02351         OFX::Log::error( true, "Instance Changed called with unknown type '%s' of object '%s'", changedType.c_str(), changedName.c_str() );
02352         }
02353 }
02354 
02355 /** @brief Library side end instance changed action */
02356 void endInstanceChangedAction( OfxImageEffectHandle handle, OFX::PropertySet inArgs )
02357 {
02358         ImageEffect* effectInstance = retrieveImageEffectPointer( handle );
02359 
02360         std::string reasonStr       = inArgs.propGetString( kOfxPropChangeReason );
02361         InstanceChangeReason reason = mapInstanceChangedReasonStringToEnum( reasonStr );
02362 
02363         // and call the plugin client code
02364         effectInstance->endChanged( reason );
02365 }
02366 
02367 /** @brief The main entry point for the plugin
02368 */
02369 OfxStatus mainEntryStr( const char*          actionRaw,
02370                         const void*          handleRaw,
02371                         OfxPropertySetHandle inArgsRaw,
02372                         OfxPropertySetHandle outArgsRaw,
02373                         const char*          plugname )
02374 {
02375         OFX::Log::print( "********************************************************************************" );
02376         OFX::Log::print( "START mainEntry (%s)", actionRaw );
02377         OFX::Log::indent();
02378         OfxStatus stat = kOfxStatReplyDefault;
02379 
02380         // Cast the raw handle to be an image effect handle, because that is what it is
02381         OfxImageEffectHandle handle = (OfxImageEffectHandle) handleRaw;
02382 
02383         // Turn the arguments into wrapper objects to make our lives easier
02384         OFX::PropertySet inArgs( inArgsRaw );
02385         OFX::PropertySet outArgs( outArgsRaw );
02386 
02387         try
02388         {
02389                 // turn the action into a std::string
02390                 std::string action( actionRaw );
02391                 OfxPlugInfoMap::iterator it = plugInfoMap.find( plugname );
02392                 if( it == plugInfoMap.end() )
02393                         BOOST_THROW_EXCEPTION( std::logic_error( "Action not recognized: " + action ) );
02394                 OFX::PluginFactory* factory = it->second._factory;
02395 
02396                 // figure the actions
02397                 if( action == kOfxActionLoad )
02398                 {
02399                         // call the support load function, param-less
02400                         OFX::Private::loadAction();
02401 
02402                         // call the plugin side load action, param-less
02403                         factory->load();
02404 
02405                         // got here, must be good
02406                         stat = kOfxStatOK;
02407                 }
02408                 // figure the actions
02409                 else if( action == kOfxActionUnload )
02410                 {
02411                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, true, true, true );
02412 
02413                         // call the plugin side unload action, param-less, should be called, eve if the stat above failed!
02414                         factory->unload();
02415 
02416                         // call the support unload function, param-less
02417                         OFX::Private::unloadAction( plugname );
02418 
02419                         // got here, must be good
02420                         stat = kOfxStatOK;
02421                 }
02422 
02423                 else if( action == kOfxActionDescribe )
02424                 {
02425                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true );
02426 
02427                         // make the plugin descriptor
02428                         ImageEffectDescriptor* desc = new ImageEffectDescriptor( handle );
02429 
02430                         // validate the host
02431                         OFX::Validation::validatePluginDescriptorProperties( fetchEffectProps( handle ) );
02432 
02433                         //  and pass it to the plugin to do something with it
02434 
02435                         factory->describe( *desc );
02436 
02437                         // add it to our map
02438                         gEffectDescriptors[plugname][eContextNone] = desc;
02439 
02440                         // got here, must be good
02441                         stat = kOfxStatOK;
02442                 }
02443                 else if( action == kOfxImageEffectActionDescribeInContext )
02444                 {
02445                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true );
02446 
02447                         // make the plugin descriptor and pass it to the plugin to do something with it
02448                         ImageEffectDescriptor* desc = new ImageEffectDescriptor( handle );
02449 
02450                         // figure the context and map it to an enum
02451                         std::string contextStr = inArgs.propGetString( kOfxImageEffectPropContext );
02452                         EContext context    = mapContextStringToEnum( contextStr );
02453 
02454                         // validate the host
02455                         OFX::Validation::validatePluginDescriptorProperties( fetchEffectProps( handle ) );
02456 
02457                         // call plugin descibe in context
02458                         factory->describeInContext( *desc, context );
02459 
02460                         // add it to our map
02461                         gEffectDescriptors[plugname][context] = desc;
02462 
02463                         // got here, must be good
02464                         stat = kOfxStatOK;
02465                 }
02466                 else if( action == kOfxActionCreateInstance )
02467                 {
02468                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true );
02469 
02470                         // fetch the effect props to figure the context
02471                         PropertySet effectProps = fetchEffectProps( handle );
02472 
02473                         // get the context and turn it into an enum
02474                         std::string str     = effectProps.propGetString( kOfxImageEffectPropContext );
02475                         EContext context = mapContextStringToEnum( str );
02476 
02477                         // make the image effect instance for this context
02478                         /*ImageEffect *instance = */ factory->createInstance( handle, context );
02479 
02480                         // validate the plugin handle's properties
02481                         OFX::Validation::validatePluginInstanceProperties( fetchEffectProps( handle ) );
02482 
02483                         // got here, must be good
02484                         stat = kOfxStatOK;
02485                 }
02486                 else if( action == kOfxActionDestroyInstance )
02487                 {
02488                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true );
02489 
02490                         // fetch our pointer out of the props on the handle
02491                         ImageEffect* instance = retrieveImageEffectPointer( handle );
02492 
02493                         // kill it
02494                         delete instance;
02495 
02496                         // got here, must be good
02497                         stat = kOfxStatOK;
02498                 }
02499                 else if( action == kOfxImageEffectActionRender )
02500                 {
02501                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true );
02502 
02503                         // call the render action skin
02504                         renderAction( handle, inArgs );
02505 
02506                         // got here, must be good
02507                         stat = kOfxStatOK;
02508                 }
02509                 else if( action == kOfxImageEffectActionBeginSequenceRender )
02510                 {
02511                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true );
02512 
02513                         // call the begin render action skin
02514                         beginSequenceRenderAction( handle, inArgs );
02515                 }
02516                 else if( action == kOfxImageEffectActionEndSequenceRender )
02517                 {
02518                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true );
02519 
02520                         // call the begin render action skin
02521                         endSequenceRenderAction( handle, inArgs );
02522                 }
02523                 else if( action == kOfxImageEffectActionIsIdentity )
02524                 {
02525                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false );
02526 
02527                         // call the identity action, if it is, return OK
02528                         if( isIdentityAction( handle, inArgs, outArgs ) )
02529                         stat = kOfxStatOK;
02530                 }
02531                 else if( action == kOfxImageEffectActionGetRegionOfDefinition )
02532                 {
02533                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false );
02534 
02535                         // call the rod action, return OK if it does something
02536                         if( regionOfDefinitionAction( handle, inArgs, outArgs ) )
02537                         stat = kOfxStatOK;
02538                 }
02539                 else if( action == kOfxImageEffectActionGetRegionsOfInterest )
02540                 {
02541                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false );
02542 
02543                         // call the RoI action, return OK if it does something
02544                         if( regionsOfInterestAction( handle, inArgs, outArgs, plugname ) )
02545                         stat = kOfxStatOK;
02546                 }
02547                 else if( action == kOfxImageEffectActionGetFramesNeeded )
02548                 {
02549                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, false );
02550 
02551                         // call the frames needed action, return OK if it does something
02552                         if( framesNeededAction( handle, inArgs, outArgs, plugname ) )
02553                         stat = kOfxStatOK;
02554                 }
02555                 else if( action == kOfxImageEffectActionGetClipPreferences )
02556                 {
02557                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, false );
02558 
02559                         // call the frames needed action, return OK if it does something
02560                         if( clipPreferencesAction( handle, outArgs, plugname ) )
02561                         stat = kOfxStatOK;
02562                 }
02563                 else if( action == kOfxActionPurgeCaches )
02564                 {
02565                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true );
02566 
02567                         // fetch our pointer out of the props on the handle
02568                         ImageEffect* instance = retrieveImageEffectPointer( handle );
02569 
02570                         // purge 'em
02571                         instance->purgeCaches();
02572                 }
02573                 else if( action == kOfxActionSyncPrivateData )
02574                 {
02575                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true );
02576 
02577                         // fetch our pointer out of the props on the handle
02578                         ImageEffect* instance = retrieveImageEffectPointer( handle );
02579 
02580                         // and sync it
02581                         instance->syncPrivateData();
02582                 }
02583                 else if( action == kOfxImageEffectActionGetTimeDomain )
02584                 {
02585                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, false );
02586 
02587                         // call the instance changed action
02588                         if( getTimeDomainAction( handle, outArgs ) )
02589                         stat = kOfxStatOK;
02590 
02591                         // fetch our pointer out of the props on the handle
02592                         /*ImageEffect *instance = */ retrieveImageEffectPointer( handle );
02593 
02594                 }
02595                 else if( action == kOfxActionBeginInstanceChanged )
02596                 {
02597                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true );
02598 
02599                         // call the instance changed action
02600                         beginInstanceChangedAction( handle, inArgs );
02601                 }
02602                 else if( action == kOfxActionInstanceChanged )
02603                 {
02604                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true );
02605 
02606                         // call the instance changed action
02607                         instanceChangedAction( handle, inArgs );
02608                 }
02609                 else if( action == kOfxActionEndInstanceChanged )
02610                 {
02611                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, false, true );
02612 
02613                         // call the instance changed action
02614                         endInstanceChangedAction( handle, inArgs );
02615                 }
02616                 else if( action == kOfxActionBeginInstanceEdit )
02617                 {
02618                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true );
02619 
02620                         // fetch our pointer out of the props on the handle
02621                         ImageEffect* instance = retrieveImageEffectPointer( handle );
02622 
02623                         // call the begin edit function
02624                         instance->beginEdit();
02625                 }
02626                 else if( action == kOfxActionEndInstanceEdit )
02627                 {
02628                         checkMainHandles( actionRaw, handleRaw, inArgsRaw, outArgsRaw, false, true, true );
02629 
02630                         // fetch our pointer out of the props on the handle
02631                         ImageEffect* instance = retrieveImageEffectPointer( handle );
02632 
02633                         // call the end edit function
02634                         instance->endEdit();
02635                 }
02636                 else if( actionRaw )
02637                 {
02638                         OFX::Log::error( true, "Unknown action '%s'.", actionRaw );
02639                 }
02640                 else
02641                 {
02642                         OFX::Log::error( true, "Requested action was a null pointer." );
02643                 }
02644         }
02645         catch( boost::exception& e )
02646         {
02647                 std::cerr << tuttle::common::Color::get()->_error;
02648                 std::cerr << "__________" << std::endl;
02649                 /*
02650                 [tuttle::exception::tag_devMessage*] = DPX: Unable to open file.
02651                 [OFX::tag_ofxStatus*] = kOfxStatErrValue
02652                 [boost::errinfo_file_name_*] = /datas/tmp/master32secsh01.0014.dpx
02653                 */
02654                 if( const boost::error_info_sstream* const messageException = boost::get_error_info< tuttle::exception::user >(e) )
02655                 {
02656                         std::cerr << "Error: " << *messageException << std::endl;
02657                 }
02658                 else
02659                 {
02660                         std::cerr << "Error: " "No message." << std::endl;
02661                 }
02662                 if( const std::string* const filenameException = boost::get_error_info< ::boost::errinfo_file_name >(e) )
02663                 {
02664                         std::cerr << "filename: \"" << *filenameException << "\"" << std::endl;
02665                 }
02666 
02667         #ifndef TUTTLE_PRODUCTION
02668                 std::cerr << "__________" << std::endl;
02669                 std::cerr << "* Caught boost::exception on action " << actionRaw << std::endl;
02670         #ifndef BOOST_EXCEPTION_DISABLE
02671                 std::cerr << boost::diagnostic_information(e);
02672         #endif
02673 //              std::cerr << "* inArgs: " << inArgs << std::endl;
02674                 std::cerr << "----------" << std::endl;
02675                 std::cerr << "* Backtrace" << std::endl;
02676                 std::cerr << boost::trace(e);
02677         #endif
02678                 std::cerr << "__________" << std::endl;
02679                 std::cerr << tuttle::common::Color::get()->_std;
02680                 
02681                 /// @todo there is an assert in boost::get_error_info here. Why?
02682                 if( const ::OfxStatus* status = boost::get_error_info< ::OFX::ofxStatus >( e ) )
02683                 {
02684                         stat = *status;
02685                 }
02686                 else
02687                 {
02688                         stat = kOfxStatFailed;
02689                 }
02690         }
02691 
02692         // catch suite exceptions
02693         catch( OFX::Exception::Suite& e )
02694         {
02695                 std::cerr << "Caught OFX::Exception::Suite (" << e.what() << ")" << std::endl;
02696                 stat = e.status();
02697         }
02698 
02699         // catch host inadequate exceptions
02700         catch( OFX::Exception::HostInadequate& e )
02701         {
02702                 std::cerr << "Caught OFX::Exception::HostInadequate (" << e.what() << ")" << std::endl;
02703                 stat = kOfxStatErrMissingHostFeature;
02704         }
02705 
02706         // catch exception due to a property being unknown to the host, implies something wrong with host if not caught further down
02707         catch( OFX::Exception::PropertyUnknownToHost& e )
02708         {
02709                 std::cerr << "Caught OFX::Exception::PropertyUnknownToHost (" << e.what() << ")" << std::endl;
02710                 stat = kOfxStatErrMissingHostFeature;
02711         }
02712 
02713         // catch memory
02714         catch( std::bad_alloc& e )
02715         {
02716                 std::cerr << "Caught std::bad_alloc (" << e.what() << ")" << std::endl;
02717                 stat = kOfxStatErrMemory;
02718         }
02719 
02720         // catch a custom client exception, if defined
02721         #ifdef OFX_CLIENT_EXCEPTION_TYPE
02722         catch( OFX_CLIENT_EXCEPTION_TYPE& e )
02723         {
02724                 std::cerr << "Caught OFX_CLIENT_EXCEPTION (" << e.what() << ")" << std::endl;
02725                 stat = OFX_CLIENT_EXCEPTION_HANDLER( e, plugname );
02726         }
02727         #endif
02728 
02729         // catch all exceptions
02730         catch( std::exception& e )
02731         {
02732                 std::cerr << "Caught std::exception on action " << actionRaw << " (" << e.what() << ")" << std::endl;
02733                 stat = kOfxStatFailed;
02734         }
02735 
02736         // Catch anything else, unknown
02737         catch( ... )
02738         {
02739                 std::cerr << "Caught Unknown exception (file:" << __FILE__ << " line:" << __LINE__ << ")" << std::endl;
02740                 stat = kOfxStatFailed;
02741         }
02742 
02743         OFX::Log::outdent();
02744         OFX::Log::print( "STOP mainEntry (%s)\n", actionRaw );
02745         return stat;
02746 }
02747 
02748 /** @brief The plugin function that gets passed the host structure. */
02749 void setHost( OfxHost* host )
02750 {
02751         gHost = host;
02752 }
02753 
02754 OfxPlugInfo generatePlugInfo( PluginFactory* factory )
02755 {
02756         std::auto_ptr<OfxPlugin> ofxPlugin( new OfxPlugin() );
02757         ofxPlugin->pluginApi          = kOfxImageEffectPluginApi;
02758         ofxPlugin->apiVersion         = kOfxImageEffectPluginApiVersion;
02759         ofxPlugin->pluginIdentifier   = factory->getID().c_str();
02760         ofxPlugin->pluginVersionMajor = factory->getMajorVersion();
02761         ofxPlugin->pluginVersionMinor = factory->getMinorVersion();
02762         ofxPlugin->setHost            = OFX::Private::setHost;
02763         ofxPlugin->mainEntry          = factory->getMainEntry();
02764         return OfxPlugInfo( factory, ofxPlugin.release() );
02765 }
02766 
02767 } // namespace Private
02768 
02769 /** @brief Fetch's a suite from the host and logs errors */
02770 void* fetchSuite( const char* suiteName, int suiteVersion, bool optional )
02771 {
02772         void* suite = Private::gHost->fetchSuite( Private::gHost->host, suiteName, suiteVersion );
02773 
02774         if( suite == 0 )
02775         {
02776                 if( optional )
02777                         OFX::Log::warning( suite == 0, "Could not fetch the optional suite '%s' version %d.", suiteName, suiteVersion );
02778                 else
02779                         OFX::Log::error( suite == 0, "Could not fetch the mandatory suite '%s' version %d.", suiteName, suiteVersion );
02780         }
02781         if( !optional && suite == 0 )
02782         BOOST_THROW_EXCEPTION( OFX::Exception::HostInadequate( suiteName ) );
02783         return suite;
02784 }
02785 
02786 } // namespace OFX
02787 
02788 namespace OFX {
02789 namespace Plugin {
02790 void getPluginIDs( OFX::PluginFactoryArray& ids );
02791 }
02792 }
02793 
02794 
02795 void init()
02796 {
02797         using namespace OFX;
02798         using namespace OFX::Private;
02799         if( gHasInit )
02800         {
02801                 return;
02802         }
02803 
02804         ::OFX::Plugin::getPluginIDs( plugIDs );
02805         ofxPlugs.reserve( plugIDs.size() );
02806 
02807         BOOST_FOREACH( PluginFactory* factory, plugIDs )
02808         {
02809                 OfxPlugInfo info = generatePlugInfo( factory );
02810                 const std::string newID = factory->getUID();
02811                 plugInfoMap[newID] = info;
02812                 ofxPlugs.push_back( info._plug );
02813         }
02814         gHasInit = true;
02815 }
02816 
02817 
02818 /** @brief, mandated function returning the number of plugins, which is always 1 */
02819 OfxExport int OfxGetNumberOfPlugins( void )
02820 {
02821         init();
02822         return static_cast<int>( OFX::plugIDs.size() );
02823 }
02824 
02825 /** @brief, mandated function returning the nth plugin
02826 *
02827 * We call the plugin side defined OFX::Plugin::getPluginID function to find out what to set.
02828 */
02829 OfxExport OfxPlugin* OfxGetPlugin( int nth )
02830 {
02831         init();
02832         const int numPlugs = static_cast<int>( OFX::Private::plugInfoMap.size() );
02833         OFX::Log::error( nth >= numPlugs, "Host attempted to get plugin %d, when there is only %d plugin(s).", nth, numPlugs );
02834         BOOST_ASSERT( nth < numPlugs  );
02835         OFX::Log::error( OFX::Private::ofxPlugs[nth] == NULL, "Host attempted to get plugin %d, but it is unloaded.", nth );
02836         BOOST_ASSERT( OFX::Private::ofxPlugs[nth] != NULL );
02837         return OFX::Private::ofxPlugs[nth];
02838 }
02839