TuttleOFX
1
|
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 }