TuttleOFX  1
InputBufferPlugin.cpp
Go to the documentation of this file.
00001 #include "InputBufferPlugin.hpp"
00002 #include "InputBufferDefinitions.hpp"
00003 
00004 #include <pointerParam.hpp>
00005 
00006 #include <tuttle/common/ofx/imageEffect.hpp>
00007 
00008 #include <boost/assert.hpp>
00009 #include <boost/scoped_ptr.hpp>
00010 #include <boost/lexical_cast.hpp>
00011 #include <boost/cstdint.hpp>
00012 
00013 namespace tuttle {
00014 namespace plugin {
00015 namespace inputBuffer {
00016 
00017 using namespace memoryBuffer;
00018 
00019 namespace {
00020 inline std::size_t bitDepthMemorySize( const OFX::EBitDepth e )
00021 {
00022         switch( e )
00023         {
00024                 case OFX::eBitDepthUByte:
00025                         return sizeof( boost::uint8_t );
00026                 case OFX::eBitDepthUShort:
00027                         return sizeof( boost::uint16_t );
00028                 case OFX::eBitDepthFloat:
00029                         return sizeof( float );
00030                 case OFX::eBitDepthNone:
00031                 case OFX::eBitDepthCustom:
00032                         return 0;
00033         }
00034         BOOST_ASSERT( false );
00035         return 0;
00036 }
00037 
00038 inline std::size_t numberOfComponents( const OFX::EPixelComponent c )
00039 {
00040         switch( c )
00041         {
00042                 case OFX::ePixelComponentRGBA:
00043                         return 4;
00044                 case OFX::ePixelComponentRGB:
00045                         return 3;
00046                 case OFX::ePixelComponentAlpha:
00047                         return 1;
00048                 case OFX::ePixelComponentNone:
00049                         return 0;
00050                 case OFX::ePixelComponentCustom:
00051                         BOOST_THROW_EXCEPTION( exception::Value()
00052                             << exception::user() + "Can't retrieve the number of values inside a custom pixel component." );
00053         }
00054         BOOST_ASSERT( false );
00055         return 0;
00056 }
00057 
00058 }
00059 
00060 
00061 InputBufferPlugin::InputBufferPlugin( OfxImageEffectHandle handle )
00062 : OFX::ImageEffect( handle )
00063 {
00064         _clipDst = fetchClip( kOfxImageEffectOutputClipName );
00065 
00066         _paramInputMode = fetchChoiceParam( kParamInputMode );
00067         _paramInputBufferPointer = fetchStringParam( kParamInputBufferPointer );
00068         _paramInputCallbackPointer = fetchStringParam( kParamInputCallbackPointer );
00069         _paramInputCallbackCustomData = fetchStringParam( kParamInputCustomData );
00070         _paramInputCallbackDestroyCustomData = fetchStringParam( kParamInputCallbackDestroyCustomData );
00071         
00072         _paramSize = fetchInt2DParam( kParamSize );
00073         _paramRowByteSize = fetchIntParam( kParamRowBytesSize );
00074         _paramPixelAspectRatio = fetchDoubleParam( kParamPixelAspectRatio );
00075         _paramFramerate = fetchDoubleParam( kParamFramerate );
00076         _paramPixelComponents = fetchChoiceParam( kParamPixelComponents );
00077         _paramBitDepth = fetchChoiceParam( kParamBitDepth );
00078         _paramField = fetchChoiceParam( kParamField );
00079         _paramOrientation = fetchChoiceParam( kParamOrientation );
00080         
00081         _paramTimeDomain = fetchDouble2DParam( kParamTimeDomain );
00082         
00083         // init temporary values
00084         _callbackMode_time = 0;
00085         _callbackMode_imgSize.x = 0;
00086         _callbackMode_imgSize.y = 0;
00087         _callbackMode_rowSizeBytes = 0;
00088         _callbackMode_imgPointer = NULL;
00089         
00090         changedParam( OFX::InstanceChangedArgs(), kParamInputMode );
00091 }
00092 
00093 InputBufferPlugin::~InputBufferPlugin()
00094 {
00095 }
00096 
00097 InputBufferProcessParams InputBufferPlugin::getProcessParams( const OfxTime time ) const
00098 {
00099         InputBufferProcessParams params;
00100         params._mode = static_cast<EParamInputMode>( _paramInputMode->getValue() );
00101         
00102         params._inputBuffer = static_cast<unsigned char*>( stringToPointer( _paramInputBufferPointer->getValueAtTime( time ) ) );
00103         params._callbackPtr = reinterpret_cast<CallbackInputImagePtr>( stringToPointer( _paramInputCallbackPointer->getValue() ) );
00104         params._customDataPtr = static_cast<CustomDataPtr>( stringToPointer( _paramInputCallbackCustomData->getValue() ) );
00105         params._callbackDestroyPtr = reinterpret_cast<CallbackDestroyCustomDataPtr>( stringToPointer( _paramInputCallbackDestroyCustomData->getValue() ) );
00106         
00107         const OfxPointI imgSize = _paramSize->getValueAtTime( time );
00108         params._width = imgSize.x;
00109         params._height = imgSize.y;
00110         params._rowByteSize = _paramRowByteSize->getValueAtTime( time );
00111         
00112         params._pixelAspectRatio = _paramPixelAspectRatio->getValue();
00113         params._framerate = _paramFramerate->getValue();
00114         
00115         switch( static_cast<EParamPixelComponent>(_paramPixelComponents->getValue()) )
00116         {
00117         case eParamPixelComponentAlpha:
00118                 params._pixelComponents = OFX::ePixelComponentAlpha;
00119                 break;
00120         case eParamPixelComponentRGB:
00121                 params._pixelComponents = OFX::ePixelComponentRGB;
00122                 break;
00123         case eParamPixelComponentRGBA:
00124                 params._pixelComponents = OFX::ePixelComponentRGBA;
00125                 break;
00126         }
00127         switch( static_cast<EParamBitDepth>(_paramBitDepth->getValue()) )
00128         {
00129         case eParamBitDepthUByte:
00130                 params._bitDepth = OFX::eBitDepthUByte;
00131                 break;
00132         case eParamBitDepthUShort:
00133                 params._bitDepth = OFX::eBitDepthUShort;
00134                 break;
00135         case eParamBitDepthFloat:
00136                 params._bitDepth = OFX::eBitDepthFloat;
00137                 break;
00138         }
00139         switch( static_cast<EParamField>(_paramField->getValue()) )
00140         {
00141         case eParamFieldNone:
00142                 params._field = OFX::eFieldNone;
00143                 break;
00144         case eParamFieldBoth:
00145                 params._field = OFX::eFieldBoth;
00146                 break;
00147         case eParamFieldLower:
00148                 params._field = OFX::eFieldLower;
00149                 break;
00150         case eParamFieldUpper:
00151                 params._field = OFX::eFieldUpper;
00152                 break;
00153         }
00154         params._orientation = static_cast<EParamOrientation>(_paramOrientation->getValue());
00155         
00156         return params;
00157 }
00158 
00159 void InputBufferPlugin::changedParam( const OFX::InstanceChangedArgs& args, const std::string& paramName )
00160 {
00161         if( paramName == kParamInputMode )
00162         {
00163                 const EParamInputMode mode = static_cast<EParamInputMode>( _paramInputMode->getValue() );
00164                 
00165                 _paramInputBufferPointer->setIsSecretAndDisabled( (mode != eParamInputModeBufferPointer) );
00166                 _paramInputCallbackPointer->setIsSecretAndDisabled( (mode != eParamInputModeCallbackPointer) );
00167                 _paramInputCallbackCustomData->setIsSecretAndDisabled( (mode != eParamInputModeCallbackPointer) );
00168         }
00169         else if( paramName == kParamInputBufferPointer )
00170         {
00171                 _paramInputMode->setValue( eParamInputModeBufferPointer );
00172         }
00173         else if( ( paramName == kParamInputCallbackPointer ) ||
00174                      ( paramName == kParamInputCustomData ) )
00175         {
00176                 _paramInputMode->setValue( eParamInputModeCallbackPointer );
00177         }
00178         else if( paramName == kParamInputCustomData )
00179         {
00180                 InputBufferProcessParams params = getProcessParams(args.time);
00181                 if( params._callbackDestroyPtr != NULL && _tempStoreCustomDataPtr != NULL )
00182                         params._callbackDestroyPtr( _tempStoreCustomDataPtr );
00183                 _tempStoreCustomDataPtr = static_cast<CustomDataPtr>( stringToPointer( _paramInputCallbackCustomData->getValue() ) );
00184         }
00185 }
00186 
00187 bool InputBufferPlugin::getTimeDomain( OfxRangeD& range )
00188 {
00189         _paramTimeDomain->getValue( range.min, range.max );
00190         return true;
00191 }
00192 
00193 void InputBufferPlugin::getClipPreferences( OFX::ClipPreferencesSetter& clipPreferences )
00194 {
00195         OfxRangeD range;
00196         _paramTimeDomain->getValue( range.min, range.max );
00197         InputBufferProcessParams params = getProcessParams( range.min );
00198         
00199         clipPreferences.setOutputFrameVarying( params._mode == eParamInputModeCallbackPointer );
00200         clipPreferences.setClipComponents( *_clipDst, params._pixelComponents );
00201         clipPreferences.setClipBitDepth( *_clipDst, params._bitDepth );
00202         clipPreferences.setPixelAspectRatio( *_clipDst, params._pixelAspectRatio );
00203         clipPreferences.setOutputFrameRate( params._framerate );
00204         clipPreferences.setOutputFielding( params._field );
00205 }
00206 
00207 bool InputBufferPlugin::getRegionOfDefinition( const OFX::RegionOfDefinitionArguments& args, OfxRectD& rod )
00208 {
00209         InputBufferProcessParams params = getProcessParams( args.time );
00210         switch( params._mode )
00211         {
00212                 case eParamInputModeBufferPointer:
00213                 {
00214                         rod.x1 = 0;
00215                         rod.y1 = 0;
00216                         OfxPointI imgSize = _paramSize->getValueAtTime( args.time );
00217                         rod.x2 = imgSize.x;
00218                         rod.y2 = imgSize.y;
00219                         break;
00220                 }
00221                 case eParamInputModeCallbackPointer:
00222                 {
00223                         callbackMode_updateImage( args.time, params );
00224                         rod.x1 = 0;
00225                         rod.y1 = 0;
00226                         rod.x2 = _callbackMode_imgSize.x;
00227                         rod.y2 = _callbackMode_imgSize.y;
00228                         break;
00229                 }
00230         }
00231         return true;
00232 }
00233 
00234 void InputBufferPlugin::callbackMode_updateImage( const OfxTime time, const InputBufferProcessParams& params )
00235 {
00236         if( _callbackMode_time == time && _callbackMode_imgPointer != NULL )
00237                 return;
00238         
00239         if( ! params._callbackPtr )
00240                 return;
00241         
00242         _callbackMode_time = time;
00243         params._callbackPtr(
00244                         time, params._customDataPtr,
00245                         (void**)&(_callbackMode_imgPointer),
00246                         &_callbackMode_imgSize.x,
00247                         &_callbackMode_imgSize.y,
00248                         &_callbackMode_rowSizeBytes
00249                 );
00250 }
00251 
00252 /**
00253  * @brief The overridden render function
00254  * @param[in]   args     Rendering parameters
00255  */
00256 void InputBufferPlugin::render( const OFX::RenderArguments &args )
00257 {
00258         // @todo: add an OpenFX extension to setup the image buffer pointer
00259         //        from the plugin.
00260         // If the host supports this extension, we only need to set the pointer,
00261         // else we need to do a buffer copy.
00262 
00263         // User parameters
00264         InputBufferProcessParams params = getProcessParams( args.time );
00265         
00266 
00267 //      if()
00268 //      {
00269 //              // Set the buffer pointer
00270 //      }
00271 //      else
00272         {
00273                 // Buffer Copy
00274 
00275                 // fetch the destination image
00276                 boost::scoped_ptr<OFX::Image> dst( _clipDst->fetchImage( args.time ) );
00277                 if( !dst.get() )
00278                         BOOST_THROW_EXCEPTION( exception::ImageNotReady()
00279                                 << exception::dev() + "Error on clip " + quotes(_clipDst->name()) );
00280                 if( dst->getRowDistanceBytes() == 0 )
00281                         BOOST_THROW_EXCEPTION( exception::WrongRowBytes()
00282                                 << exception::dev() + "Error on clip " + quotes(_clipDst->name()) );
00283 
00284                 OfxRectI dstPixelRod;
00285                 if( OFX::getImageEffectHostDescription()->hostName == "uk.co.thefoundry.nuke" )
00286                 {
00287                         // bug in nuke, getRegionOfDefinition() on OFX::Image returns bounds
00288                         dstPixelRod = _clipDst->getPixelRod( args.time, args.renderScale );
00289                 }
00290                 else
00291                 {
00292                         dstPixelRod = dst->getRegionOfDefinition();
00293                 }
00294                 OfxPointI dstPixelRodSize;
00295                 dstPixelRodSize.x = ( dstPixelRod.x2 - dstPixelRod.x1 );
00296                 dstPixelRodSize.y = ( dstPixelRod.y2 - dstPixelRod.y1 );
00297 
00298                 unsigned char* inputImageBufferPtr = NULL;
00299                 int rowBytesDistanceSize = 0;
00300                 switch( params._mode )
00301                 {
00302                         case eParamInputModeBufferPointer:
00303                         {
00304                                 inputImageBufferPtr = params._inputBuffer;
00305                                 rowBytesDistanceSize = params._rowByteSize;
00306                                 break;
00307                         }
00308                         case eParamInputModeCallbackPointer:
00309                         {
00310                                 callbackMode_updateImage( args.time, params );
00311                                 inputImageBufferPtr = _callbackMode_imgPointer;
00312                                 rowBytesDistanceSize = _callbackMode_rowSizeBytes;
00313                                 break;
00314                         }
00315                 }
00316 //              TUTTLE_TLOG_VAR( TUTTLE_INFO, (void*)inputImageBufferPtr );
00317 
00318                 const std::size_t nbComponents = numberOfComponents( params._pixelComponents );
00319                 const std::size_t bitDepthMemSize = bitDepthMemorySize( params._bitDepth );
00320                 int widthBytesSize = dstPixelRodSize.x * nbComponents * bitDepthMemSize;
00321                 if( rowBytesDistanceSize == 0 )
00322                         rowBytesDistanceSize = widthBytesSize;
00323 
00324                 // Copy the image
00325 //              TUTTLE_TLOG_VAR( TUTTLE_INFO, nbComponents );
00326 //              TUTTLE_TLOG_VAR( TUTTLE_INFO, bitDepthMemSize );
00327 //              TUTTLE_TLOG_VAR( TUTTLE_INFO, widthBytesSize );
00328 //              TUTTLE_TLOG_VAR( TUTTLE_INFO, (void*)inputImageBufferPtr );
00329 //              TUTTLE_TLOG_VAR( TUTTLE_INFO, dstPixelRodSize.x );
00330 //              TUTTLE_TLOG_VAR( TUTTLE_INFO, dstPixelRodSize.y );
00331 //              TUTTLE_TLOG_VAR( TUTTLE_INFO, rowBytesDistanceSize );
00332 //              TUTTLE_TLOG_VAR( TUTTLE_INFO, widthBytesSize );
00333                 switch( params._orientation )
00334                 {
00335                         case eParamOrientationFromBottomToTop:
00336                         {
00337                                 for( int y = 0; y < dstPixelRodSize.y; ++y )
00338                                 {
00339                                         memcpy( dst->getPixelAddress( 0, y ), inputImageBufferPtr + y * rowBytesDistanceSize, widthBytesSize );
00340                                 }
00341                                 break;
00342                         }
00343                         case eParamOrientationFromTopToBottom:
00344                         {
00345                                 for( int y = 0; y < dstPixelRodSize.y; ++y )
00346                                 {
00347                                         memcpy( dst->getPixelAddress( 0, y ), inputImageBufferPtr + (dstPixelRodSize.y-y) * rowBytesDistanceSize, widthBytesSize );
00348                                 }
00349                                 break;
00350                         }
00351                 }
00352                 
00353                 switch( params._mode )
00354                 {
00355                         case eParamInputModeCallbackPointer:
00356                         {
00357                                 // We duplicated the image buffer to a buffer allocated by the host.
00358                                 // Now we can destroy the customData.
00359                                 if( params._callbackDestroyPtr != NULL )
00360                                         params._callbackDestroyPtr( params._customDataPtr );
00361                                 _callbackMode_imgPointer = NULL;
00362                                 break;
00363                         }
00364                         case eParamInputModeBufferPointer:
00365                                 break;
00366                 }
00367         }
00368 }
00369 
00370 
00371 }
00372 }
00373 }