TuttleOFX  1
TuttleOFX/libraries/tuttle/src/tuttle/plugin/context/WriterPlugin.cpp
Go to the documentation of this file.
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 }