TuttleOFX
1
|
00001 #include "WriterPlugin.hpp" 00002 00003 #include <ofxCore.h> 00004 00005 #include <boost/filesystem/operations.hpp> 00006 #include <boost/scoped_ptr.hpp> 00007 00008 #include <cstdio> 00009 00010 namespace tuttle { 00011 namespace plugin { 00012 00013 namespace bfs = boost::filesystem; 00014 00015 WriterPlugin::WriterPlugin( OfxImageEffectHandle handle ) 00016 : ImageEffectGilPlugin( handle ) 00017 , _oneRender( false ) 00018 , _oneRenderAtTime( 0 ) 00019 { 00020 _clipSrc = fetchClip( kOfxImageEffectSimpleSourceClipName ); 00021 _clipDst = fetchClip( kOfxImageEffectOutputClipName ); 00022 _paramFilepath = fetchStringParam( kTuttlePluginFilename ); 00023 _paramRenderButton = fetchPushButtonParam( kParamWriterRender ); 00024 _paramRenderAlways = fetchBooleanParam( kParamWriterRenderAlways ); 00025 _paramCopyToOutput = fetchBooleanParam( kParamWriterCopyToOutput ); 00026 _paramBitDepth = fetchChoiceParam( kTuttlePluginBitDepth ); 00027 _paramPremult = fetchBooleanParam( kParamPremultiplied ); 00028 _paramExistingFile = fetchChoiceParam( kParamWriterExistingFile ); 00029 _paramForceNewRender = fetchIntParam( kParamWriterForceNewRender ); 00030 _isSequence = _filePattern.initFromDetection( _paramFilepath->getValue( ) ); 00031 } 00032 00033 WriterPlugin::~WriterPlugin( ) 00034 { 00035 } 00036 00037 void WriterPlugin::changedParam( const OFX::InstanceChangedArgs& args, const std::string& paramName ) 00038 { 00039 if( paramName == kTuttlePluginFilename ) 00040 { 00041 _isSequence = _filePattern.initFromDetection( _paramFilepath->getValue( ) ); 00042 } 00043 else if( paramName == kParamWriterRender ) 00044 { 00045 _oneRender = true; 00046 _oneRenderAtTime = args.time; 00047 // modify the plugin to force a new render 00048 _paramForceNewRender->setValue( _paramForceNewRender->getValue( ) + 1 ); 00049 } 00050 } 00051 00052 void WriterPlugin::getClipPreferences( OFX::ClipPreferencesSetter& clipPreferences ) 00053 { 00054 // If pattern detected (frame varying on time) 00055 clipPreferences.setOutputFrameVarying( varyOnTime( ) ); 00056 } 00057 00058 bool WriterPlugin::isIdentity( const OFX::RenderArguments& args, OFX::Clip*& identityClip, OfxTime& identityTime ) 00059 { 00060 EParamWriterExistingFile existingFile = static_cast<EParamWriterExistingFile>(_paramExistingFile->getValue()); 00061 if( existingFile != eParamWriterExistingFile_overwrite ) 00062 { 00063 const std::string filepath = getAbsoluteFilenameAt( args.time ); 00064 const bool fileExists = boost::filesystem::exists( filepath ); 00065 00066 switch( existingFile ) 00067 { 00068 case eParamWriterExistingFile_error: 00069 { 00070 if( fileExists ) 00071 BOOST_THROW_EXCEPTION( exception::FileExist(filepath) ); 00072 break; 00073 } 00074 case eParamWriterExistingFile_reader: 00075 { 00076 BOOST_ASSERT(false); 00077 // Not implemented 00078 } 00079 case eParamWriterExistingFile_skip: 00080 { 00081 if( fileExists ) 00082 { 00083 // We declare an empty clip as identity to disable the process of this node. 00084 // This is not in the OpenFX standard. So this option only exist on TuttleOFX host. 00085 identityClip = NULL; 00086 identityTime = 0; 00087 TUTTLE_TLOG_TRACE("[Plugin Writer] Identity node: " << this->getName() << " at time: " << args.time << ", file already exist:" << filepath); 00088 return true; 00089 } 00090 break; 00091 } 00092 case eParamWriterExistingFile_overwrite: 00093 BOOST_ASSERT(false); 00094 } 00095 } 00096 00097 // little hack for the push button Render 00098 if( _oneRender && _oneRenderAtTime == args.time ) 00099 { 00100 return false; 00101 } 00102 if( OFX::getImageEffectHostDescription( )->hostIsBackground ) 00103 { 00104 return false; 00105 } 00106 if( _paramRenderAlways->getValue( ) ) 00107 { 00108 return false; 00109 } 00110 identityClip = _clipSrc; 00111 identityTime = args.time; 00112 return true; 00113 } 00114 00115 void WriterPlugin::beginSequenceRender( const OFX::BeginSequenceRenderArguments& args ) 00116 { 00117 boost::filesystem::path dir( getAbsoluteDirectory( ) ); 00118 if( !boost::filesystem::exists( dir ) ) 00119 { 00120 boost::filesystem::create_directories( dir ); 00121 } 00122 } 00123 00124 void WriterPlugin::render( const OFX::RenderArguments& args ) 00125 { 00126 _oneRender = false; 00127 00128 TUTTLE_LOG_INFO( " --> " << getAbsoluteFilenameAt( args.time ) ); 00129 00130 if( _paramCopyToOutput->getValue() ) 00131 { 00132 boost::scoped_ptr<OFX::Image> src( _clipSrc->fetchImage( args.time ) ); 00133 boost::scoped_ptr<OFX::Image> dst( _clipDst->fetchImage( args.time ) ); 00134 00135 // Copy buffer 00136 const OfxRectI bounds = dst->getBounds(); 00137 TUTTLE_TLOG_VAR( TUTTLE_TRACE, bounds ); 00138 if( src->isLinearBuffer() && dst->isLinearBuffer() ) 00139 { 00140 TUTTLE_TLOG( TUTTLE_TRACE, "isLinearBuffer" ); 00141 const std::size_t imageDataBytes = dst->getBoundsImageDataBytes(); 00142 TUTTLE_TLOG_VAR( TUTTLE_TRACE, imageDataBytes ); 00143 if( imageDataBytes ) 00144 { 00145 void* dataSrcPtr = src->getPixelAddress( bounds.x1, bounds.y1 ); 00146 void* dataDstPtr = dst->getPixelAddress( bounds.x1, bounds.y1 ); 00147 memcpy( dataDstPtr, dataSrcPtr, imageDataBytes ); 00148 } 00149 } 00150 else 00151 { 00152 const std::size_t rowBytesToCopy = dst->getBoundsRowDataBytes(); 00153 for( int y = bounds.y1; y < bounds.y2; ++y ) 00154 { 00155 void* dataSrcPtr = src->getPixelAddress( bounds.x1, y ); 00156 void* dataDstPtr = dst->getPixelAddress( bounds.x1, y ); 00157 memcpy( dataDstPtr, dataSrcPtr, rowBytesToCopy ); 00158 } 00159 } 00160 } 00161 } 00162 00163 } 00164 }