TuttleOFX  1
AVReaderPlugin.cpp
Go to the documentation of this file.
00001 #include "AVReaderPlugin.hpp"
00002 #include "AVReaderProcess.hpp"
00003 #include "AVReaderDefinitions.hpp"
00004 
00005 #include <libav/LibAVVideoReader.hpp>
00006 
00007 #include <boost/gil/gil_all.hpp>
00008 #include <boost/filesystem.hpp>
00009 
00010 namespace tuttle {
00011 namespace plugin {
00012 namespace av {
00013 namespace reader {
00014 
00015 using namespace boost::gil;
00016 namespace fs = boost::filesystem;
00017 
00018 AVReaderPlugin::AVReaderPlugin( OfxImageEffectHandle handle )
00019         : AVOptionPlugin( handle )
00020         , _errorInFile( false )
00021         , _initReader( false )
00022 {
00023         // We want to render a sequence
00024         setSequentialRender( true );
00025 
00026         _clipDst = fetchClip( kOfxImageEffectOutputClipName );
00027         _paramFilepath = fetchStringParam( kTuttlePluginFilename );
00028         _paramBitDepth = fetchChoiceParam( kTuttlePluginBitDepth );
00029         _paramUseCustomSAR = fetchBooleanParam( kParamUseCustomSAR );
00030         _paramCustomSAR = fetchDoubleParam( kParamCustomSAR );
00031 
00032         updateVisibleTools();
00033 }
00034 
00035 void AVReaderPlugin::updateVisibleTools()
00036 {
00037         OFX::InstanceChangedArgs args( this->timeLineGetTime() );
00038         changedParam( args, kParamUseCustomSAR );
00039 }
00040 
00041 AVReaderParams AVReaderPlugin::getProcessParams() const
00042 {
00043         AVReaderParams params;
00044 
00045         _paramFilepath->getValue( params._filepath );
00046         return params;
00047 }
00048 
00049 /**
00050  * @brief Open the video if not already opened.
00051  * @return If the video file is now open,
00052  *         else the file doesn't exist, is unrecognized or is corrupted.
00053  */
00054 bool AVReaderPlugin::ensureVideoIsOpen()
00055 {
00056         if( _reader.isOpen() )
00057                 return true;
00058 
00059         // if we have not already tried
00060         if( !_errorInFile )
00061         {
00062                 _errorInFile = !_reader.open( _paramFilepath->getValue() );
00063         }
00064         return !_errorInFile;
00065 }
00066 
00067 void AVReaderPlugin::changedParam( const OFX::InstanceChangedArgs& args, const std::string& paramName )
00068 {
00069         ReaderPlugin::changedParam( args, paramName );
00070         if( paramName == kTuttlePluginFilename )
00071         {
00072                 _errorInFile = false;
00073         }
00074         else if( paramName == kParamUseCustomSAR )
00075         {
00076                 const bool useCustomSAR = _paramUseCustomSAR->getValue();
00077                 _paramCustomSAR->setIsSecretAndDisabled( !useCustomSAR );
00078         }
00079         else if( paramName == kParamCustomSAR )
00080         {
00081                 const bool useCustomSAR = _paramUseCustomSAR->getValue();
00082                 if( ! useCustomSAR )
00083                 {
00084                         // If we set a customSAR and the useCustomSAR param is not enabled,
00085                         // use it directly!
00086                         // This could not happen in a UI application, but only from command line or from API.
00087                         _paramUseCustomSAR->setValue( true );
00088                 }
00089         }
00090 }
00091 
00092 void AVReaderPlugin::getClipPreferences( OFX::ClipPreferencesSetter& clipPreferences )
00093 {
00094         ReaderPlugin::getClipPreferences( clipPreferences );
00095         clipPreferences.setOutputFrameVarying( true );
00096         clipPreferences.setClipComponents( *_clipDst, OFX::ePixelComponentRGBA );
00097         if( getExplicitBitDepthConversion() == eParamReaderBitDepthAuto )
00098         {
00099                 clipPreferences.setClipBitDepth( *_clipDst, OFX::eBitDepthUByte ); /// @todo tuttle: some video format may need other bit depth (how we can detect this ?)
00100         }
00101 
00102         if( !ensureVideoIsOpen() )
00103                 return;
00104 
00105         // options depending on input file
00106         const bool useCustomSAR = _paramUseCustomSAR->getValue();
00107         const double customSAR = _paramCustomSAR->getValue();
00108         clipPreferences.setPixelAspectRatio( *_clipDst, useCustomSAR ? customSAR : _reader.aspectRatio() );
00109         clipPreferences.setOutputFrameRate( _reader.fps() );
00110         
00111         // Setup fielding
00112         switch( _reader.interlacment() )
00113         {
00114                 case  eInterlacmentNone:
00115                 {
00116                         clipPreferences.setOutputFielding( OFX::eFieldNone );
00117                         break;
00118                 }
00119                 case  eInterlacmentUpper:
00120                 {
00121                         clipPreferences.setOutputFielding( OFX::eFieldUpper );
00122                         break;
00123                 }
00124                 case  eInterlacmentLower:
00125                 {
00126                         clipPreferences.setOutputFielding( OFX::eFieldLower );
00127                         break;
00128                 }
00129         }
00130 }
00131 
00132 bool AVReaderPlugin::getTimeDomain( OfxRangeD& range )
00133 {
00134         if( !ensureVideoIsOpen() )
00135                 return false;
00136 
00137         range.min = 0.0;
00138         range.max = (double)(_reader.nbFrames()-1);
00139         
00140         //TUTTLE_LOG_VAR2( TUTTLE_INFO, range.min, range.max );
00141         
00142         return true;
00143 }
00144 
00145 bool AVReaderPlugin::getRegionOfDefinition( const OFX::RegionOfDefinitionArguments& args, OfxRectD& rod )
00146 {
00147         if( !ensureVideoIsOpen() )
00148                 return false;
00149 
00150         const bool useCustomSAR = _paramUseCustomSAR->getValue();
00151         const double customSAR = _paramCustomSAR->getValue();
00152 
00153         rod.x1 = 0;
00154         rod.x2 = _reader.width() * ( useCustomSAR ? customSAR : _reader.aspectRatio() );
00155         rod.y1 = 0;
00156         rod.y2 = _reader.height();
00157         return true;
00158 }
00159 
00160 void AVReaderPlugin::beginSequenceRender( const OFX::BeginSequenceRenderArguments& args )
00161 {
00162         ensureVideoIsOpen();
00163 }
00164 
00165 /**
00166  * @brief The overridden render function
00167  * @param[in]   args     Rendering parameters
00168  */
00169 void AVReaderPlugin::render( const OFX::RenderArguments& args )
00170 {
00171         if( !ensureVideoIsOpen() )
00172         {
00173                 BOOST_THROW_EXCEPTION( exception::Unknown() );
00174         }
00175 
00176         if( !_initReader )
00177         {
00178                 // set Format parameters
00179                 AVFormatContext* avFormatContext;
00180                 avFormatContext = avformat_alloc_context();
00181                 setParameters( _reader, eAVParamFormat, (void*)avFormatContext, AV_OPT_FLAG_DECODING_PARAM, 0 );
00182                 avformat_free_context( avFormatContext );
00183                 
00184                 // set Video Codec parameters
00185                 AVCodecContext* avCodecContext;
00186                 
00187         #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT( 53, 8, 0 )
00188                 avCodecContext = avcodec_alloc_context();
00189                 // deprecated in the same version
00190                 //avCodecContext = avcodec_alloc_context2( AVMEDIA_TYPE_UNKNOWN );
00191         #else
00192                 AVCodec* avCodec = NULL;
00193                 avCodecContext = avcodec_alloc_context3( avCodec );
00194         #endif
00195                 setParameters( _reader, eAVParamVideo, (void*)avCodecContext, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM, 0 );
00196         }
00197         
00198         doGilRender<AVReaderProcess>( *this, args );
00199 }
00200 
00201 void AVReaderPlugin::endSequenceRender( const OFX::EndSequenceRenderArguments& args )
00202 {
00203         _reader.close();
00204 }
00205 
00206 }
00207 }
00208 }
00209 }