#include <string>
#include <map>
#include <stdexcept>
#include <iostream>
#include "ofxImageEffect.h"
#include "ofxMemory.h"
#include "ofxMultiThread.h"
#include "ofxMessage.h"
#include "ofxLog.H"
#if defined __APPLE__ || defined linux || defined __FreeBSD__
# define EXPORT __attribute__((visibility("default")))
#elif defined _WIN32
# define EXPORT OfxExport
#else
# error Not building on your operating system quite yet
#endif
static OfxHost *gHost;
static OfxImageEffectSuiteV1 *gEffectSuite;
static OfxPropertySuiteV1 *gPropSuite;
static OfxInteractSuiteV1 *gInteractSuite;
static OfxParameterSuiteV1 *gParamSuite;
static OfxMemorySuiteV1 *gMemorySuite;
static OfxMultiThreadSuiteV1 *gThreadSuite;
static OfxMessageSuiteV1 *gMessageSuite;
static const void *
fetchSuite(const char *suiteName, int suiteVersion, bool optional = false)
{
const void *suite = gHost->fetchSuite(gHost->host, suiteName, suiteVersion);
if(optional)
OFX::logWarning(suite == 0, "Could not fetch the optional suite '%s' version %d;", suiteName, suiteVersion);
else
OFX::logError(suite == 0, "Could not fetch the mandatory suite '%s' version %d;", suiteName, suiteVersion);
if(!optional && suite == 0) throw kOfxStatErrMissingHostFeature;
return suite;
}
class PropertySet {
protected :
int _propLogMessages;
OfxPropertySetHandle _propHandle;
public :
PropertySet(OfxPropertySetHandle h = 0)
: _propLogMessages(0)
, _propHandle(h)
{}
virtual ~PropertySet();
void propSetHandle(OfxPropertySetHandle h) { _propHandle = h;}
OfxStatus propSet(const char *property, void *value, int idx = 0);
OfxStatus propSet(const char *property, const std::string &value, int idx = 0);
OfxStatus propSet(const char *property, double value, int idx = 0);
OfxStatus propSet(const char *property, int value, int idx = 0);
OfxStatus propGet(const char *property, void * &value, int idx = 0) const;
OfxStatus propGet(const char *property, double &value, int idx = 0) const;
OfxStatus propGet(const char *property, int &value, int idx = 0) const;
OfxStatus propGet(const char *property, std::string &value, int idx = 0) const;
OfxStatus propGetN(const char *property, int *values, int N) const;
OfxStatus propGetN(const char *property, double *values, int N) const;
OfxStatus propGetN(const char *property, std::string *values, int N) const;
OfxStatus propGetDimension(const char *property, int &size) const;
void propEnableLog(void) {--_propLogMessages; }
void propDisableLog(void) {++_propLogMessages; }
};
struct PropertyValueOnion {
std::string vString;
int vInt;
double vDouble;
void *vPointer;
PropertyValueOnion(void) {}
PropertyValueOnion(const char *s) : vString(s) {}
PropertyValueOnion(int i) : vInt(i) {}
PropertyValueOnion(double d) : vDouble(d) {}
PropertyValueOnion(void *p) : vPointer(p) {}
PropertyValueOnion &operator = (const char *v) {vString = v; return *this;}
PropertyValueOnion &operator = (const std::string &v) {vString = v; return *this;}
PropertyValueOnion &operator = (void *v) {vPointer = v; return *this;}
PropertyValueOnion &operator = (int v) {vInt = v; return *this;}
PropertyValueOnion &operator = (double v) {vDouble = v; return *this;}
operator const char * () {return vString.c_str();}
operator std::string &() {return vString;}
operator int &() {return vInt;}
operator double &() {return vDouble;}
operator void * &() {return vPointer;}
};
class PropertyDescription
{
public :
enum TypeEnum {ePointer,
eInt,
eString,
eDouble};
const char * _name;
int _dimension; TypeEnum _ilk;
PropertyValueOnion *_defs; int _nDefs;
PropertyValueOnion *_wantedVals; int _nWantedVals;
PropertyValueOnion *_currentVals; int _nCurrentVals;
protected :
template <class T> void
initialise( const char *nm, int dim, TypeEnum ilk,
const T *wantedVals, int nWantedVals, const T *defs, int nDefs)
{
_name = nm;
_dimension = dim;
_ilk = ilk;
_defs = _wantedVals = _currentVals = 0;
_nDefs = _nWantedVals = _nCurrentVals = 0;
if(nWantedVals) {
_nWantedVals = nWantedVals;
_wantedVals = new PropertyValueOnion[nWantedVals];
for(int i = 0; i < nWantedVals; i++)
_wantedVals[i] = wantedVals[i];
}
if(nDefs) {
_nDefs = nDefs;
_defs = new PropertyValueOnion[_nDefs];
for(int i = 0; i < nDefs; i++)
_defs[i] = defs[i];
}
}
public :
virtual ~PropertyDescription(void)
{
delete [ ] _currentVals;
delete [ ] _wantedVals;
delete [ ] _defs;
}
PropertyDescription(const char *nm, int dim, const char * const *wantedVals, int nV, const char * const *defs, int nD)
{
initialise(nm, dim, eString, wantedVals, nV, defs, nD);
}
PropertyDescription(const char *nm, int dim, const char *value, bool setValue, const char *def, bool hasDefault)
{
initialise(nm, dim, eString,
&value, setValue ? 1 : 0,
&def, hasDefault ? 1 : 0);
}
PropertyDescription(const char *nm, int dim, const int *wantedVals, int nV, const int *defs, int nD)
{
initialise(nm, dim, eInt, wantedVals, nV, defs, nD);
}
PropertyDescription(const char *nm, int dim, int value, bool setValue, int def, bool hasDefault)
{
initialise(nm, dim, eInt,
&value, setValue ? 1 : 0,
&def, hasDefault ? 1 : 0);
}
PropertyDescription(const char *nm, int dim, const double *wantedVals, int nV, const double *defs, int nD)
{
initialise(nm, dim, eDouble, wantedVals, nV, defs, nD);
}
PropertyDescription(const char *nm, int dim, double value, bool setValue, double def, bool hasDefault)
{
initialise(nm, dim, eDouble,
&value, setValue ? 1 : 0,
&def, hasDefault ? 1 : 0);
}
PropertyDescription(const char *nm, int dim, void *value, bool setValue, void *def, bool hasDefault)
{
initialise(nm, dim, ePointer,
&value, setValue ? 1 : 0,
&def, hasDefault ? 1 : 0);
}
void checkProperty(PropertySet &propSet); void checkDefault(PropertySet &propSet); void retrieveValue(PropertySet &propSet); void setValue(PropertySet &propSet); };
class PropertySetDescription : PropertySet {
protected :
const char *_setName;
PropertyDescription *_descriptions;
int _nDescriptions;
std::map<std::string, PropertyDescription *> _descriptionsByName;
public :
PropertySetDescription(const char *setName, OfxPropertySetHandle handle, PropertyDescription *v, int nV);
void checkProperties(bool logOrdinaryMessages = false); void checkDefaults(bool logOrdinaryMessages = false); void retrieveValues(bool logOrdinaryMessages = false); void setValues(bool logOrdinaryMessages = false); PropertyDescription *findDescription(const std::string &name);
int intPropValue(const std::string &name, int idx = 0);
double doublePropValue(const std::string &name, int idx = 0);
void *pointerPropValue(const std::string &name, int idx = 0);
const std::string &stringPropValue(const std::string &name, int idx = 0);
};
static const char *
mapStatus(OfxStatus stat)
{
switch(stat) {
case kOfxStatOK : return "kOfxStatOK";
case kOfxStatFailed : return "kOfxStatFailed";
case kOfxStatErrFatal : return "kOfxStatErrFatal";
case kOfxStatErrUnknown : return "kOfxStatErrUnknown";
case kOfxStatErrMissingHostFeature : return "kOfxStatErrMissingHostFeature";
case kOfxStatErrUnsupported : return "kOfxStatErrUnsupported";
case kOfxStatErrExists : return "kOfxStatErrExists";
case kOfxStatErrFormat : return "kOfxStatErrFormat";
case kOfxStatErrMemory : return "kOfxStatErrMemory";
case kOfxStatErrBadHandle : return "kOfxStatErrBadHandle";
case kOfxStatErrBadIndex : return "kOfxStatErrBadIndex";
case kOfxStatErrValue : return "kOfxStatErrValue";
case kOfxStatReplyYes : return "kOfxStatReplyYes";
case kOfxStatReplyNo : return "kOfxStatReplyNo";
case kOfxStatReplyDefault : return "kOfxStatReplyDefault";
case kOfxStatErrImageFormat : return "kOfxStatErrImageFormat";
}
return "UNKNOWN STATUS CODE";
}
PropertySet::~PropertySet()
{
}
OfxStatus
PropertySet::propSet(const char *property, void *value, int idx)
{
OfxStatus stat = gPropSuite->propSetPointer(_propHandle, property, idx, value);
OFX::logError(stat != kOfxStatOK, "Failed on setting pointer property %s[%d] to %p, host returned status %s;", property, idx, value, mapStatus(stat));
if(stat == kOfxStatOK && _propLogMessages <= 0)
OFX::logPrint("Set pointer property %s[%d] = %p;", property, idx, value);
return stat;
}
OfxStatus
PropertySet::propSet(const char *property, const std::string &value, int idx)
{
OfxStatus stat = gPropSuite->propSetString(_propHandle, property, idx, value.c_str());
OFX::logError(stat != kOfxStatOK, "Failed on setting string property %s[%d] to '%s', host returned status %s;", property, idx, value.c_str(), mapStatus(stat));
if(stat == kOfxStatOK && _propLogMessages <= 0)
OFX::logPrint("Set string property %s[%d] = '%s';", property, idx, value.c_str());
return stat;
}
OfxStatus
PropertySet::propSet(const char *property, double value, int idx)
{
OfxStatus stat = gPropSuite->propSetDouble(_propHandle, property, idx, value);
OFX::logError(stat != kOfxStatOK, "Failed on setting double property %s[%d] to %g, host returned status %s;", property, idx, value, mapStatus(stat));
if(stat == kOfxStatOK && _propLogMessages <= 0)
OFX::logPrint("Set double property %s[%d] = %g;", property, idx, value);
return stat;
}
OfxStatus
PropertySet::propSet(const char *property, int value, int idx)
{
OfxStatus stat = gPropSuite->propSetInt(_propHandle, property, idx, value);
OFX::logError(stat != kOfxStatOK, "Failed on setting int property %s[%d] to %d, host returned status '%s';", property, idx, value, mapStatus(stat));
if(stat == kOfxStatOK && _propLogMessages <= 0)
OFX::logPrint("Set int property %s[%d] = %d;", property, idx, value);
return stat;
}
OfxStatus
PropertySet::propGet(const char *property, void * &value, int idx) const
{
OfxStatus stat = gPropSuite->propGetPointer(_propHandle, property, idx, &value);
OFX::logError(stat != kOfxStatOK, "Failed on fetching pointer property %s[%d], host returned status %s;", property, idx, mapStatus(stat));
if(stat == kOfxStatOK && _propLogMessages <= 0)
OFX::logPrint("Fetched pointer property %s[%d] = %p;", property, idx, value);
return stat;
}
OfxStatus
PropertySet::propGet(const char *property, double &value, int idx) const
{
OfxStatus stat = gPropSuite->propGetDouble(_propHandle, property, idx, &value);
OFX::logError(stat != kOfxStatOK, "Failed on fetching double property %s[%d], host returned status %s;", property, idx, mapStatus(stat));
if(stat == kOfxStatOK && _propLogMessages <= 0)
OFX::logPrint("Fetched double property %s[%d] = %g;", property, idx, value);
return stat;
}
OfxStatus
PropertySet::propGetN(const char *property, double *values, int N) const
{
OfxStatus stat = gPropSuite->propGetDoubleN(_propHandle, property, N, values);
OFX::logError(stat != kOfxStatOK, "Failed on fetching multiple double property %s X %d, host returned status %s;", property, N, mapStatus(stat));
if(stat == kOfxStatOK && _propLogMessages <= 0) {
OFX::logPrint("Fetched multiple double property %s X %d;", property, N);
for(int i = 0; i < N; i++) {
OFX::logPrint(" %s[%d] = %g;", property, i, values[i]);
}
}
return stat;
}
OfxStatus
PropertySet::propGetN(const char *property, int *values, int N) const
{
OfxStatus stat = gPropSuite->propGetIntN(_propHandle, property, N, values);
OFX::logError(stat != kOfxStatOK, "Failed on fetching multiple int property %s X %d, host returned status %s;", property, N, mapStatus(stat));
if(stat == kOfxStatOK && _propLogMessages <= 0) {
OFX::logPrint("Fetched multiple int property %s X %d;", property, N);
for(int i = 0; i < N; i++) {
OFX::logPrint(" %s[%d] = %d;", property, i, values[i]);
}
}
return stat;
}
OfxStatus
PropertySet::propGet(const char *property, int &value, int idx) const
{
OfxStatus stat = gPropSuite->propGetInt(_propHandle, property, idx, &value);
OFX::logError(stat != kOfxStatOK, "Failed on fetching int property %s[%d], host returned status %s;", property, idx, mapStatus(stat));
if(stat == kOfxStatOK && _propLogMessages <= 0)
OFX::logPrint("Fetched int property %s[%d] = %d;", property, idx, value);
return stat;
}
OfxStatus
PropertySet::propGet(const char *property, std::string &value, int idx) const
{
char *str;
OfxStatus stat = gPropSuite->propGetString(_propHandle, property, idx, &str);
OFX::logError(stat != kOfxStatOK, "Failed on fetching string property %s[%d], host returned status %s;", property, idx, mapStatus(stat));
if(kOfxStatOK == stat) {
value = str;
if(_propLogMessages <= 0)
OFX::logPrint("Fetched string property %s[%d] = '%s';", property, idx, value.c_str());
}
else {
value = "";
}
return stat;
}
OfxStatus
PropertySet::propGetN(const char *property, std::string *values, int N) const
{
char **strs = new char * [N];
OfxStatus stat = gPropSuite->propGetStringN(_propHandle, property, N, strs);
OFX::logError(stat != kOfxStatOK, "Failed on fetching multiple string property %s X %d, host returned status %s;", property, N, mapStatus(stat));
if(kOfxStatOK == stat) {
if(_propLogMessages <= 0) OFX::logPrint("Fetched multiple string property %s X %d;", property, N);
for(int i = 0; i < N; i++) {
values[i] = strs[i];
if(_propLogMessages <= 0) OFX::logPrint(" %s[%d] = '%s';", property, i, strs[i]);
}
}
else {
for(int i = 0; i < N; i++) {
values[i] = "";
}
}
delete [] strs;
return stat;
}
OfxStatus
PropertySet::propGetDimension(const char *property, int &size) const
{
OfxStatus stat = gPropSuite->propGetDimension(_propHandle, property, &size);
OFX::logError(stat != kOfxStatOK, "Failed on fetching dimension for property %s, host returned status %s;", property, mapStatus(stat));
return stat;
}
void
PropertyDescription::checkProperty(PropertySet &propSet)
{
int dimension;
OfxStatus stat = propSet.propGetDimension(_name, dimension);
if(stat == kOfxStatOK) {
if(_dimension != -1)
OFX::logError(dimension != _dimension, "Host reports property '%s' has dimension %d, it should be %d;", _name, dimension, _dimension);
if(dimension > 0) {
void *vP;
int vI;
double vD;
std::string vS;
switch(_ilk) {
case PropertyDescription::ePointer : propSet.propGet(_name, vP); break;
case PropertyDescription::eInt : propSet.propGet(_name, vI); break;
case PropertyDescription::eString : propSet.propGet(_name, vS); break;
case PropertyDescription::eDouble : propSet.propGet(_name, vD); break;
}
}
}
}
void PropertyDescription::checkDefault(PropertySet &propSet)
{
if(_nDefs > 0) {
int hostDimension;
OfxStatus stat = propSet.propGetDimension(_name, hostDimension);
(void)stat;
OFX::logError(hostDimension != _nDefs, "Host reports default dimension of '%s' is %d, which is different to the default value %d;", _name, hostDimension, _nDefs);
int N = hostDimension < _nDefs ? hostDimension : _nDefs;
for(int i = 0; i < N; i++) {
void *vP;
int vI;
double vD;
std::string vS;
switch(_ilk) {
case PropertyDescription::ePointer :
propSet.propGet(_name, vP, i);
OFX::logError(vP != (void *) _defs[i], "Default value of %s[%d] = %p, it should be %p;", _name, i, vP, (void *) _defs[i]);
break;
case PropertyDescription::eInt :
propSet.propGet(_name, vI, i);
OFX::logError(vI != (int) _defs[i], "Default value of %s[%d] = %d, it should be %d;", _name, i, vI, (int) _defs[i]);
break;
case PropertyDescription::eString :
propSet.propGet(_name, vS, i);
OFX::logError(vS != _defs[i].vString, "Default value of %s[%d] = '%s', it should be '%s';", _name, i, vS.c_str(), _defs[i].vString.c_str());
break;
case PropertyDescription::eDouble :
propSet.propGet(_name, vD, i);
OFX::logError(vD != (double) _defs[i], "Default value of %s[%d] = %g, it should be %g;", _name, i, vD, (double) _defs[i]);
break;
}
}
}
}
void
PropertyDescription::retrieveValue(PropertySet &propSet)
{
if(_currentVals) delete [] _currentVals;
_currentVals = 0;
_nCurrentVals = 0;
int hostDimension;
OfxStatus stat = propSet.propGetDimension(_name, hostDimension);
if(stat == kOfxStatOK && hostDimension > 0) {
_nCurrentVals = hostDimension;
_currentVals = new PropertyValueOnion[hostDimension];
for(int i = 0; i < hostDimension; i++) {
void *vP;
int vI;
double vD;
std::string vS;
switch(_ilk) {
case PropertyDescription::ePointer :
stat = propSet.propGet(_name, vP, i);
_currentVals[i] = (stat == kOfxStatOK) ? vP : (void *)(0);
break;
case PropertyDescription::eInt :
stat = propSet.propGet(_name, vI, i);
_currentVals[i] = (stat == kOfxStatOK) ? vI : 0;
break;
case PropertyDescription::eString :
stat = propSet.propGet(_name, vS, i);
if(stat == kOfxStatOK)
_currentVals[i] = vS;
else
_currentVals[i] = std::string("");
break;
case PropertyDescription::eDouble :
stat = propSet.propGet(_name, vD, i);
_currentVals[i] = (stat == kOfxStatOK) ? vD : 0.0;
break;
}
}
}
}
void
PropertyDescription::setValue(PropertySet &propSet)
{
if(_nWantedVals > 0) {
int i;
for(i = 0; i < _nWantedVals; i++) {
switch(_ilk) {
case PropertyDescription::ePointer :
propSet.propSet(_name, _wantedVals[i].vPointer, i);
break;
case PropertyDescription::eInt :
propSet.propSet(_name, _wantedVals[i].vInt, i);
break;
case PropertyDescription::eString :
propSet.propSet(_name, _wantedVals[i].vString, i);
break;
case PropertyDescription::eDouble :
propSet.propSet(_name, _wantedVals[i].vDouble, i);
break;
}
}
propSet.propDisableLog();
retrieveValue(propSet);
propSet.propEnableLog();
OFX::logError(_nWantedVals != _nCurrentVals, "After setting property %s, the dimension %d is not the same as what was set %d", _name, _nCurrentVals, _nWantedVals);
int N = _nWantedVals < _nCurrentVals ? _nWantedVals : _nCurrentVals;
for(i = 0; i < N; i++) {
switch(_ilk) {
case PropertyDescription::ePointer :
OFX::logError(_wantedVals[i].vPointer != _currentVals[i].vPointer,
"After setting pointer value %s[%d] value fetched back %p not same as value set %p",
_name, i, _wantedVals[i].vPointer, _currentVals[i].vPointer);
break;
case PropertyDescription::eInt :
OFX::logError(_wantedVals[i].vInt != _currentVals[i].vInt,
"After setting int value %s[%d] value fetched back %d not same as value set %d",
_name, i, _wantedVals[i].vInt, _currentVals[i].vInt);
break;
case PropertyDescription::eString :
OFX::logError(_wantedVals[i].vString != _currentVals[i].vString,
"After setting string value %s[%d] value fetched back '%s' not same as value set '%s'",
_name, i, _wantedVals[i].vString.c_str(), _currentVals[i].vString.c_str());
break;
case PropertyDescription::eDouble :
OFX::logError(_wantedVals[i].vDouble != _currentVals[i].vDouble,
"After setting double value %s[%d] value fetched back %g not same as value set %g",
_name, i, _wantedVals[i].vDouble, _currentVals[i].vDouble);
break;
}
}
}
}
PropertySetDescription::PropertySetDescription(const char *setName, OfxPropertySetHandle handle, PropertyDescription *v, int nV)
: PropertySet(handle)
, _setName(setName)
, _descriptions(v)
, _nDescriptions(nV)
{
for(int i = 0; i < nV; i++) {
std::pair<std::string, PropertyDescription *> mePair(v[i]._name, &v[i]);
_descriptionsByName.insert(mePair);
}
}
void
PropertySetDescription::checkProperties(bool logOrdinaryMessages)
{
OFX::logPrint("PropertySetDescription::checkProperties - start(checking properties on %s);\n{", _setName);
if(!logOrdinaryMessages) propDisableLog();
for(int i = 0; i < _nDescriptions; i++) {
_descriptions[i].checkProperty(*this);
}
if(!logOrdinaryMessages) propEnableLog();
OFX::logPrint("}PropertySetDescription::checkProperties - stop;");
}
void
PropertySetDescription::checkDefaults(bool logOrdinaryMessages)
{
OFX::logPrint("PropertySetDescription::checkDefaults - start(checking default value of properties on %s);\n{", _setName);
if(!logOrdinaryMessages) propDisableLog();
for(int i = 0; i < _nDescriptions; i++) {
_descriptions[i].checkDefault(*this);
}
if(!logOrdinaryMessages) propEnableLog();
OFX::logPrint("}PropertySetDescription::checkDefaults - stop;");
}
void
PropertySetDescription::retrieveValues(bool logOrdinaryMessages)
{
OFX::logPrint("PropertySetDescription::retrieveValues - start(retrieving values of properties on %s);\n{", _setName);
if(!logOrdinaryMessages) propDisableLog();
for(int i = 0; i < _nDescriptions; i++) {
_descriptions[i].retrieveValue(*this);
}
if(!logOrdinaryMessages) propEnableLog();
OFX::logPrint("}PropertySetDescription::retrieveValues - stop;");
}
void
PropertySetDescription::setValues(bool logOrdinaryMessages)
{
OFX::logPrint("PropertySetDescription::setValues - start(retrieving values of properties on %s);\n{", _setName);
if(!logOrdinaryMessages) propDisableLog();
for(int i = 0; i < _nDescriptions; i++) {
_descriptions[i].setValue(*this);
}
if(!logOrdinaryMessages) propEnableLog();
OFX::logPrint("}PropertySetDescription::setValues - stop;");
}
PropertyDescription *
PropertySetDescription::findDescription(const std::string &name)
{
std::map<std::string, PropertyDescription *>::iterator iter;
iter = _descriptionsByName.find(name);
if (iter != _descriptionsByName.end()) {
return iter->second;
}
return 0;
}
int
PropertySetDescription::intPropValue(const std::string &name, int idx)
{
PropertyDescription *desc = 0;
desc = findDescription(name);
if(desc) {
if(idx < desc->_nCurrentVals) {
return int(desc->_currentVals[idx]);
}
}
return 0;
}
static PropertyDescription gHostPropDescription[ ] =
{
PropertyDescription(kOfxPropType, 1, "", false, kOfxTypeImageEffectHost, true),
PropertyDescription(kOfxPropName, 1, "", false, "", false),
PropertyDescription(kOfxPropLabel, 1, "", false, "", false),
PropertyDescription(kOfxImageEffectHostPropIsBackground, 1, 0, false, 0, false),
PropertyDescription(kOfxImageEffectPropSupportsOverlays, 1, 0, false, 0, false ),
PropertyDescription(kOfxImageEffectPropSupportsMultiResolution, 1, 0, false, 0, false ),
PropertyDescription(kOfxImageEffectPropSupportsTiles, 1, 0, false, 0, false ),
PropertyDescription(kOfxImageEffectPropTemporalClipAccess, 1, 0, false, 0, false ),
PropertyDescription(kOfxImageEffectPropSupportsMultipleClipDepths, 1, 0, false, 0, false ),
PropertyDescription(kOfxImageEffectPropSupportsMultipleClipPARs, 1, 0, false, 0, false ),
PropertyDescription(kOfxImageEffectPropSetableFrameRate, 1, 0, false, 0, false ),
PropertyDescription(kOfxImageEffectPropSetableFielding, 1, 0, false, 0, false ),
PropertyDescription(kOfxImageEffectPropSupportedComponents, -1, "", false, "", false ),
PropertyDescription(kOfxImageEffectPropSupportedContexts, -1, "", false, "", false ),
PropertyDescription(kOfxParamHostPropSupportsStringAnimation, 1, 0, false, 0, false ),
PropertyDescription(kOfxParamHostPropSupportsCustomInteract, 1, 0, false, 0, false ),
PropertyDescription(kOfxParamHostPropSupportsChoiceAnimation, 1, 0, false, 0, false ),
PropertyDescription(kOfxParamHostPropSupportsBooleanAnimation, 1, 0, false, 0, false ),
PropertyDescription(kOfxParamHostPropSupportsCustomAnimation, 1, 0, false, 0, false ),
PropertyDescription(kOfxParamHostPropMaxParameters, 1, 0, false, 0, false ),
PropertyDescription(kOfxParamHostPropMaxPages, 1, 0, false, 0, false ),
PropertyDescription(kOfxParamHostPropPageRowColumnCount, 2, 0, false, 0, false )
};
class HostDescription : public PropertySet {
public :
int hostIsBackground;
int supportsOverlays;
int supportsMultiResolution;
int supportsTiles;
int temporalClipAccess;
int supportsMultipleClipDepths;
int supportsMultipleClipPARs;
int supportsSetableFrameRate;
int supportsSetableFielding;
int supportsCustomAnimation;
int supportsStringAnimation;
int supportsCustomInteract;
int supportsChoiceAnimation;
int supportsBooleanAnimation;
int maxParameters;
int maxPages;
int pageRowCount;
int pageColumnCount;
HostDescription(OfxPropertySetHandle handle);
};
HostDescription *gHostDescription = 0;
HostDescription::HostDescription(OfxPropertySetHandle handle) :
PropertySet(handle) ,
hostIsBackground(false),
supportsOverlays(false),
supportsMultiResolution(false),
supportsTiles(false),
temporalClipAccess(false),
supportsMultipleClipDepths(false),
supportsMultipleClipPARs(false),
supportsSetableFrameRate(false),
supportsSetableFielding(false),
supportsCustomAnimation(false),
supportsStringAnimation(false),
supportsCustomInteract(false),
supportsChoiceAnimation(false),
supportsBooleanAnimation(false),
maxParameters(-1),
maxPages(-1),
pageRowCount(-1),
pageColumnCount(-1)
{
OFX::logPrint("HostDescription::HostDescription - start ( fetching host description);\n{");
PropertySetDescription hostPropSet("Host", handle, gHostPropDescription, sizeof(gHostPropDescription)/sizeof(PropertyDescription));
hostPropSet.checkProperties();
hostPropSet.checkDefaults();
hostPropSet.retrieveValues(true);
hostIsBackground = hostPropSet.intPropValue(kOfxImageEffectHostPropIsBackground);
supportsOverlays = hostPropSet.intPropValue(kOfxImageEffectPropSupportsOverlays);
supportsMultiResolution = hostPropSet.intPropValue(kOfxImageEffectPropSupportsMultiResolution);
supportsTiles = hostPropSet.intPropValue(kOfxImageEffectPropSupportsTiles);
temporalClipAccess = hostPropSet.intPropValue(kOfxImageEffectPropTemporalClipAccess);
supportsMultipleClipDepths = hostPropSet.intPropValue(kOfxImageEffectPropSupportsMultipleClipDepths);
supportsMultipleClipPARs = hostPropSet.intPropValue(kOfxImageEffectPropSupportsMultipleClipPARs);
supportsSetableFrameRate = hostPropSet.intPropValue(kOfxImageEffectPropSetableFrameRate);
supportsSetableFielding = hostPropSet.intPropValue(kOfxImageEffectPropSetableFielding);
supportsStringAnimation = hostPropSet.intPropValue(kOfxParamHostPropSupportsStringAnimation);
supportsCustomInteract = hostPropSet.intPropValue(kOfxParamHostPropSupportsCustomInteract);
supportsChoiceAnimation = hostPropSet.intPropValue(kOfxParamHostPropSupportsChoiceAnimation);
supportsBooleanAnimation = hostPropSet.intPropValue(kOfxParamHostPropSupportsBooleanAnimation);
supportsCustomAnimation = hostPropSet.intPropValue(kOfxParamHostPropSupportsCustomAnimation);
maxParameters = hostPropSet.intPropValue(kOfxParamHostPropMaxParameters);
maxPages = hostPropSet.intPropValue(kOfxParamHostPropMaxPages);
pageRowCount = hostPropSet.intPropValue(kOfxParamHostPropPageRowColumnCount, 0);
pageColumnCount = hostPropSet.intPropValue(kOfxParamHostPropPageRowColumnCount, 1);
OFX::logPrint("}HostDescription::HostDescription - stop;");
}
static void
testMemorySuite(void)
{
OFX::logPrint("testMemorySuite - start();\n{");
void *oneMeg;
OfxStatus stat = gMemorySuite->memoryAlloc(NULL, 1024 * 1024, &oneMeg);
OFX::logError(stat != kOfxStatOK, "OfxMemorySuiteV1::memoryAlloc failed to alloc 1MB, returned %s", mapStatus(stat));
if(stat == kOfxStatOK) {
char *lotsOfChars = (char *) oneMeg;
for(int i = 0; i < 1024 * 1024; i++) {
*lotsOfChars++ = 0;
}
stat = gMemorySuite->memoryFree(oneMeg);
OFX::logError(stat != kOfxStatOK, "OfxMemorySuiteV1::memoryFree failed to free 1MB, returned %s", mapStatus(stat));
}
OFX::logPrint("}HostDescription::HostDescription - stop;");
}
static int gLoadCount = 0;
static OfxStatus
actionLoad(void)
{
OFX::logPrint("loadAction - start();\n{");
OFX::logError(gLoadCount != 0, "Load action called more than once without unload being called;");
gLoadCount++;
OfxStatus status = kOfxStatOK;
try {
OFX::logError(gHost == 0, "Host pointer has not been set;");
if(!gHost) throw kOfxStatErrBadHandle;
if(gLoadCount == 1) {
gEffectSuite = (OfxImageEffectSuiteV1 *) fetchSuite(kOfxImageEffectSuite, 1);
gPropSuite = (OfxPropertySuiteV1 *) fetchSuite(kOfxPropertySuite, 1);
gParamSuite = (OfxParameterSuiteV1 *) fetchSuite(kOfxParameterSuite, 1);
gMemorySuite = (OfxMemorySuiteV1 *) fetchSuite(kOfxMemorySuite, 1);
gThreadSuite = (OfxMultiThreadSuiteV1 *) fetchSuite(kOfxMultiThreadSuite, 1);
gMessageSuite = (OfxMessageSuiteV1 *) fetchSuite(kOfxMessageSuite, 1);
gHostDescription = new HostDescription(gHost->host);
if(gHostDescription->supportsOverlays || gHostDescription->supportsCustomInteract)
gInteractSuite = (OfxInteractSuiteV1 *) fetchSuite(kOfxInteractSuite, 1);
testMemorySuite();
}
}
catch(int err) {
status = err;
}
OFX::logPrint("}loadAction - stop;");
return status;
}
static OfxStatus
unLoadAction(void)
{
OFX::logError(gLoadCount <= 0, "UnLoad action called without a corresponding load action having been called;");
gLoadCount--;
gEffectSuite = 0;
gPropSuite = 0;
gParamSuite = 0;
gMemorySuite = 0;
gThreadSuite = 0;
gMessageSuite = 0;
gInteractSuite = 0;
return kOfxStatOK;
}
static OfxStatus
createInstance( OfxImageEffectHandle )
{
return kOfxStatOK;
}
static OfxStatus
destroyInstance( OfxImageEffectHandle )
{
return kOfxStatOK;
}
OfxStatus
getSpatialRoD( OfxImageEffectHandle , OfxPropertySetHandle , OfxPropertySetHandle )
{
return kOfxStatOK;
}
OfxStatus
getSpatialRoI( OfxImageEffectHandle , OfxPropertySetHandle , OfxPropertySetHandle )
{
return kOfxStatOK;
}
OfxStatus
getTemporalDomain( OfxImageEffectHandle , OfxPropertySetHandle , OfxPropertySetHandle )
{
return kOfxStatOK;
}
static OfxStatus
getClipPreferences( OfxImageEffectHandle , OfxPropertySetHandle , OfxPropertySetHandle )
{
return kOfxStatOK;
}
static OfxStatus
isIdentity( OfxImageEffectHandle ,
OfxPropertySetHandle ,
OfxPropertySetHandle )
{
return kOfxStatReplyDefault;
}
static OfxStatus
instanceChanged( OfxImageEffectHandle ,
OfxPropertySetHandle ,
OfxPropertySetHandle )
{
return kOfxStatReplyDefault;
}
static OfxStatus render(OfxImageEffectHandle ,
OfxPropertySetHandle ,
OfxPropertySetHandle )
{
return kOfxStatOK;
}
static OfxStatus
describeInContext( OfxImageEffectHandle , OfxPropertySetHandle )
{
if (!OFX::logOpenFile()) {
std::cout << "Error: OFX Test Properties plugin cannot open log file " << OFX::logGetFileName() << std::endl;
}
return kOfxStatOK;
}
static const char *gSupportedContexts[] =
{
kOfxImageEffectContextGenerator,
kOfxImageEffectContextFilter,
kOfxImageEffectContextTransition,
kOfxImageEffectContextPaint,
kOfxImageEffectContextGeneral,
kOfxImageEffectContextRetimer
};
static const char *gSupportedPixelDepths[] =
{
kOfxBitDepthByte,
kOfxBitDepthShort,
kOfxBitDepthFloat
};
static PropertyDescription gPluginPropertyDescriptions[] =
{
PropertyDescription(kOfxPropType, 1, "", false, kOfxTypeImageEffect, true),
PropertyDescription(kOfxPropLabel, 1, "OFX Test Properties", true, "", false),
PropertyDescription(kOfxPropShortLabel, 1, "OFX Test Props", true, "", false),
PropertyDescription(kOfxPropLongLabel, 1, "OFX Test Properties", true, "", false),
PropertyDescription(kOfxPluginPropFilePath, 1, "", false, "", false),
PropertyDescription(kOfxImageEffectPluginPropGrouping, 1, "OFX Example", true, "", false),
PropertyDescription(kOfxImageEffectPluginPropSingleInstance, 1, 0, true, 0, true),
PropertyDescription(kOfxImageEffectPluginRenderThreadSafety, 1, kOfxImageEffectRenderFullySafe, true, kOfxImageEffectRenderFullySafe, true),
PropertyDescription(kOfxImageEffectPluginPropHostFrameThreading, 1, 0, true, 0, true),
PropertyDescription(kOfxImageEffectPluginPropOverlayInteractV1, 1, (void *)(0), true, (void *)(0), true),
PropertyDescription(kOfxImageEffectPropSupportsMultiResolution, 1, 1, true, 1, true),
PropertyDescription(kOfxImageEffectPropSupportsTiles, 1, 1, true, 1, true),
PropertyDescription(kOfxImageEffectPropTemporalClipAccess, 1, 0, true, 0, true),
PropertyDescription(kOfxImageEffectPluginPropFieldRenderTwiceAlways, 1, 1, true, 1, true),
PropertyDescription(kOfxImageEffectPropSupportsMultipleClipDepths, 1, 0, true, 0, true),
PropertyDescription(kOfxImageEffectPropSupportsMultipleClipPARs, 1, 0, true, 0, true),
PropertyDescription(kOfxImageEffectPropSupportedContexts, -1, gSupportedContexts, sizeof(gSupportedContexts)/sizeof(char *), gSupportedContexts, 0),
PropertyDescription(kOfxImageEffectPropSupportedPixelDepths, -1, gSupportedPixelDepths, sizeof(gSupportedPixelDepths)/sizeof(char *), gSupportedPixelDepths, 0)
};
static OfxStatus
actionDescribe(OfxImageEffectHandle effect)
{
OfxPropertySetHandle effectProps;
gEffectSuite->getPropertySet(effect, &effectProps);
PropertySetDescription pluginPropSet("Plugin", effectProps, gPluginPropertyDescriptions, sizeof(gPluginPropertyDescriptions)/sizeof(PropertyDescription));
pluginPropSet.checkProperties();
pluginPropSet.checkDefaults();
pluginPropSet.retrieveValues(true);
pluginPropSet.setValues();
return kOfxStatOK;
}
static void
checkMainHandles(const char *action, const void *handle, OfxPropertySetHandle inArgsHandle, OfxPropertySetHandle outArgsHandle,
bool handleCanBeNull, bool inArgsCanBeNull, bool outArgsCanBeNull)
{
if(handleCanBeNull)
OFX::logWarning(handle != 0, "Handle passed to '%s' is not null;", action);
else
OFX::logError(handle == 0, "'Handle passed to '%s' is null;", action);
if(inArgsCanBeNull)
OFX::logWarning(inArgsHandle != 0, "'inArgs' Handle passed to '%s' is not null;", action);
else
OFX::logError(inArgsHandle == 0, "'inArgs' handle passed to '%s' is null;", action);
if(outArgsCanBeNull)
OFX::logWarning(outArgsHandle != 0, "'outArgs' Handle passed to '%s' is not null;", action);
else
OFX::logError(outArgsHandle == 0, "'outArgs' handle passed to '%s' is null;", action);
if(!handleCanBeNull && !handle) throw kOfxStatErrBadHandle;
if(!inArgsCanBeNull && !inArgsHandle) throw kOfxStatErrBadHandle;
if(!outArgsCanBeNull && !outArgsHandle) throw kOfxStatErrBadHandle;
}
static OfxStatus
pluginMain(const char *action, const void *handle, OfxPropertySetHandle inArgsHandle, OfxPropertySetHandle outArgsHandle)
{
OFX::logPrint("pluginMain - start();\n{");
OFX::logPrint(" action is '%s';", action);
OfxStatus stat = kOfxStatReplyDefault;
try {
OfxImageEffectHandle effectHandle = (OfxImageEffectHandle) handle;
PropertySet inArgs(inArgsHandle);
PropertySet outArgs(outArgsHandle);
if(OFX::strEquals(action, kOfxActionLoad)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, true, true, true);
stat = actionLoad();
}
else if(OFX::strEquals(action, kOfxActionUnload)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, true, true, true);
stat = unLoadAction();
}
else if(OFX::strEquals(action, kOfxActionDescribe)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, true, true);
stat = actionDescribe(effectHandle);
}
else if(OFX::strEquals(action, kOfxActionPurgeCaches)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, true, true);
}
else if(OFX::strEquals(action, kOfxActionSyncPrivateData)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, true, true);
}
else if(OFX::strEquals(action, kOfxActionCreateInstance)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, true, true);
stat = createInstance(effectHandle);
}
else if(OFX::strEquals(action, kOfxActionDestroyInstance)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, true, true);
stat = destroyInstance(effectHandle);
}
else if(OFX::strEquals(action, kOfxActionInstanceChanged)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, true);
}
else if(OFX::strEquals(action, kOfxActionBeginInstanceChanged)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, true);
}
else if(OFX::strEquals(action, kOfxActionEndInstanceChanged)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, true);
stat = instanceChanged(effectHandle, inArgsHandle, outArgsHandle);
}
else if(OFX::strEquals(action, kOfxActionBeginInstanceEdit)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, true, true);
}
else if(OFX::strEquals(action, kOfxActionEndInstanceEdit)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, true, true);
}
else if(OFX::strEquals(action, kOfxImageEffectActionGetRegionOfDefinition)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, false);
}
else if(OFX::strEquals(action, kOfxImageEffectActionGetRegionsOfInterest)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, false);
}
else if(OFX::strEquals(action, kOfxImageEffectActionGetTimeDomain)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, true, false);
}
else if(OFX::strEquals(action, kOfxImageEffectActionGetFramesNeeded)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, false);
}
else if(OFX::strEquals(action, kOfxImageEffectActionGetClipPreferences)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, false);
stat = getClipPreferences(effectHandle, inArgsHandle, outArgsHandle);
}
else if(OFX::strEquals(action, kOfxImageEffectActionIsIdentity)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, false);
stat = isIdentity(effectHandle, inArgsHandle, outArgsHandle);
}
else if(OFX::strEquals(action, kOfxImageEffectActionRender)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, true);
stat = render(effectHandle, inArgsHandle, outArgsHandle);
}
else if(OFX::strEquals(action, kOfxImageEffectActionBeginSequenceRender)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, true);
}
else if(OFX::strEquals(action, kOfxImageEffectActionEndSequenceRender)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, true);
}
else if(OFX::strEquals(action, kOfxImageEffectActionDescribeInContext)) {
checkMainHandles(action, handle, inArgsHandle, outArgsHandle, false, false, true);
stat = describeInContext(effectHandle, inArgsHandle);
}
else {
OFX::logError(true, "Unknown action '%s';", action);
}
} catch (std::bad_alloc) {
OFX::logError(true, "OFX Plugin Memory error;");
stat = kOfxStatErrMemory;
} catch ( const std::exception& e ) {
OFX::logError(true, "OFX Plugin error: '%s';", e.what());
stat = kOfxStatErrUnknown;
} catch (int err) {
OFX::logError(true, "OFX Plugin error: '%s';", mapStatus(err));
stat = err;
} catch ( ... ) {
OFX::logError(true, "OFX Plugin error;");
stat = kOfxStatErrUnknown;
}
OFX::logPrint("}pluginMain - stop;");
return stat;
}
static void
setHostFunc(OfxHost *hostStruct)
{
OFX::logPrint("setHostFunc - start();\n{");
OFX::logError(hostStruct == 0, "host is a null pointer;");
gHost = hostStruct;
OFX::logPrint("}setHostFunc - stop;");
}
static OfxPlugin basicPlugin =
{
kOfxImageEffectPluginApi,
1,
"net.sf.openfx:PropertyTestPlugin",
1,
0,
setHostFunc,
pluginMain
};
EXPORT OfxPlugin *
OfxGetPlugin(int nth)
{
OFX::logPrint("OfxGetPlugin - start();\n{");
OFX::logPrint(" asking for %dth plugin;", nth);
OFX::logError(nth != 0, "requested plugin %d is more than the number of plugins in the file;", nth);
OFX::logPrint("}OfxGetPlugin - stop;");
if(nth == 0) return &basicPlugin;
return 0;
}
EXPORT int
OfxGetNumberOfPlugins(void)
{
OFX::logPrint("OfxGetNumberOfPlugins - start();\n{");
OFX::logPrint("}OfxGetNumberOfPlugins - stop;");
return 1;
}
class GlobalDestructor {
public :
~GlobalDestructor();
};
GlobalDestructor::~GlobalDestructor()
{
if(gHostDescription)
delete gHostDescription;
}
static GlobalDestructor globalDestructor;