change: Switch to offical OpenFX Support. Still can't compile.

This commit is contained in:
Mike Solar
2025-09-03 21:14:56 +08:00
parent 7ff76427f9
commit b649b5e1bd
198 changed files with 57444 additions and 980 deletions
+334
View File
@@ -0,0 +1,334 @@
#ifndef _ofxsCore_H_
#define _ofxsCore_H_
// Copyright OpenFX and contributors to the OpenFX project.
// SPDX-License-Identifier: BSD-3-Clause
/** @mainpage OFX Support Library
@section mainpageIntro Introduction
This support library skins the raw OFX C API with a set of C++ classes and functions that makes it easier to understand and write plug-ins to the API. Look at the examples to see how it is done.
<HR>
@section fifteenLineGuide Fifteen Line Plugin Writing Guide
- work from the examples
- you need to write the following functions....
- void OFX::Plugin::getPluginID(OFX::PluginID &id)
- gives the unique name and version numbers of the plug-in
- void OFX::Plugin::loadAction(void)
- called after the plug-in is first loaded, and before any instance has been made,
- void OFX::Plugin::unloadAction(void)
- called before the plug-in is unloaded, and all instances have been destroyed,
- void OFX::Plugin::describe(OFX::ImageEffectDescriptor &desc)
- called to describe the plugin to the host
- void OFX::Plugin::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum context)
- called to describe the plugin to the host for a context reported in OFX::Plugin::describe
- OFX::ImageEffect * OFX::Plugin::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum context)
- called when a new instance of a plug-in needs to be created. You need to derive a class from ImageEffect, new it and return it.
The OFX::ImageEffect class has a set of members you can override to do various things, like rendering an effect. Again, look at the examples.
<HR>
@section license Copyright and License
The library is Copyright OpenFX and contributors to the OpenFX project. and was
written by Bruno Nicoletti (bruno@thefoundry.co.uk).
It has been released under the GNU Lesser General Public License, see the
top of any source file for details.
*/
/** @file This file contains core code that wraps OFX 'objects' with C++ classes.
This file only holds code that is visible to a plugin implementation, and so hides much
of the direct OFX objects and any library side only functions.
*/
#ifdef _MSC_VER
#pragma warning( disable : 4290 )
#endif
#include "ofxCore.h"
#include "ofxImageEffect.h"
#include "ofxInteract.h"
#include "ofxKeySyms.h"
#include "ofxMemory.h"
#include "ofxMessage.h"
#include "ofxMultiThread.h"
#include "ofxParam.h"
#include "ofxProperty.h"
#include "ofxPixels.h"
#include <assert.h>
#include <vector>
#include <list>
#include <string>
#include <map>
#include <exception>
#include <stdexcept>
#include <sstream>
#ifdef OFX_CLIENT_EXCEPTION_HEADER
#include OFX_CLIENT_EXCEPTION_HEADER
#endif
/** @brief Defines an integer 3D point
Should migrate this to the ofxCore.h in a v1.1
*/
struct Ofx3DPointI {
int x, y, z;
};
/** @brief Defines a double precision 3D point
Should migrate this to the ofxCore.h in a v1.1
*/
struct Ofx3DPointD {
double x, y, z;
};
/** @brief Nasty macro used to define empty protected copy ctors and assign ops */
#define mDeclareProtectedAssignAndCC(CLASS) \
CLASS &operator=(const CLASS &) {assert(false); return *this;} \
CLASS(const CLASS &) {assert(false); }
/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries.
*/
namespace OFX {
/** forward class declarations */
class PropertySet;
/** @brief Enumerates the different types a property can be */
enum PropertyTypeEnum {
ePointer,
eInt,
eString,
eDouble
};
/** @brief Enumerates the reasons a plug-in instance may have had one of its values changed */
enum InstanceChangeReason {
eChangeUserEdit, /**< @brief A user actively editted something in the plugin, eg: changed the value of an integer param on an interface */
eChangePluginEdit, /**< @brief The plugin's own code changed something in the instance, eg: a callback on on param settting the value of another */
eChangeTime /**< @brief The current value of a parameter has changed because the param animates and the current time has changed */
};
/** @brief maps a status to a string for debugging purposes, note a c-str for printf */
const char * mapStatusToString(OfxStatus stat);
/** @brief namespace for OFX support lib exceptions, all derive from std::exception, calling it */
namespace Exception {
/** @brief thrown when a suite returns a dud status code
*/
class Suite : public std::exception {
protected :
OfxStatus _status;
public :
Suite(OfxStatus s) : _status(s) {}
OfxStatus status(void) const {return _status;}
operator OfxStatus() const {return _status;}
/** @brief reimplemented from std::exception */
virtual const char * what () const noexcept {return mapStatusToString(_status);}
};
/** @brief Exception indicating that a host doesn't know about a property that is should do */
class PropertyUnknownToHost : public std::exception {
protected :
std::string _what;
public :
PropertyUnknownToHost(const char *what) : _what(what) {}
virtual ~PropertyUnknownToHost() noexcept {}
/** @brief reimplemented from std::exception */
virtual const char * what () const noexcept
{
return _what.c_str();
}
};
/** @brief exception indicating that the host thinks a property has an illegal value */
class PropertyValueIllegalToHost : public std::exception {
protected :
std::string _what;
public :
PropertyValueIllegalToHost(const char *what) : _what(what) {}
virtual ~PropertyValueIllegalToHost() noexcept {}
/** @brief reimplemented from std::exception */
virtual const char * what () const noexcept
{
return _what.c_str();
}
};
/** @brief exception indicating a request for a named thing exists (eg: a param), but is of the wrong type, should never make it back to the main entry
indicates a logical error in the code. Asserts are raised in debug code in these situations.
*/
class TypeRequest : public std::exception {
protected :
std::string _what;
public :
TypeRequest(const char *what) : _what(what) {}
virtual ~TypeRequest() noexcept {}
/** @brief reimplemented from std::exception */
virtual const char * what () const noexcept
{
return _what.c_str();
}
};
////////////////////////////////////////////////////////////////////////////////
// These exceptions are to be thrown by the plugin if it hits a problem, the
// code managing the main entry will trap the exception and return a suitable
// status code to the host.
/** @brief exception indicating a required host feature is missing */
class HostInadequate : public std::exception {
protected :
std::string _what;
public :
HostInadequate(const char *what) : _what(what) {}
virtual ~HostInadequate() noexcept {}
/** @brief reimplemented from std::exception */
virtual const char * what () const noexcept
{
return _what.c_str();
}
};
}; // end of Exception namespace
/** @brief Throws an @ref OFX::Exception::Suite depending on the status flag passed in */
void
throwSuiteStatusException(OfxStatus stat);
void
throwHostMissingSuiteException(std::string name);
/** @brief This struct is used to return an identifier for the plugin by the function @ref OFX:Plugin::getPlugin.
The members correspond to those in the OfxPlugin struct defined in ofxCore.h.
*/
class ImageEffectDescriptor;
class ImageEffect;
/** @brief This class wraps up an OFX property set */
class PropertySet {
protected :
/** @brief The raw property handle */
OfxPropertySetHandle _propHandle;
/** @brief Class static, whether we are logging each property action */
static int _gPropLogging;
/** @brief Do not throw an exception if a host returns 'unsupported' when setting a property */
static bool _gThrowOnUnsupported;
public :
/** @brief turns on logging of property access functions */
static void propEnableLogging(void) {++_gPropLogging;}
/** @brief turns off logging of property access functions */
static void propDisableLogging(void) {--_gPropLogging;}
/** @brief Do we throw an exception if a host returns 'unsupported' when setting a property. Default is true */
static void setThrowOnUnsupportedProperties(bool v) {_gThrowOnUnsupported = v;}
/** @brief Do we throw an exception if a host returns 'unsupported' when setting a property. Default is true */
static bool getThrowOnUnsupportedProperties(void) {return _gThrowOnUnsupported;}
/** @brief construct a property set */
PropertySet(OfxPropertySetHandle h = 0) : _propHandle(h) {}
virtual ~PropertySet();
/** @brief set the handle to use for this set */
void propSetHandle(OfxPropertySetHandle h) { _propHandle = h;}
/** @brief return the handle for this property set */
OfxPropertySetHandle propSetHandle(void) const {return _propHandle;}
int propGetDimension(const char* property, bool throwOnFailure = true) const;
void propReset(const char* property);
// set single values
void propSetPointer(const char* property, void *value, int idx, bool throwOnFailure = true);
void propSetString(const char* property, const std::string &value, int idx, bool throwOnFailure = true);
void propSetDouble(const char* property, double value, int idx, bool throwOnFailure = true);
void propSetInt(const char* property, int value, int idx, bool throwOnFailure = true);
// set multiple values
void propSetDoubleN(const char* property, const double *value, int count, bool throwOnFailure = true);
void propSetPointer(const char* property, void *value, bool throwOnFailure = true)
{propSetPointer(property, value, 0, throwOnFailure);}
void propSetString(const char* property, const std::string &value, bool throwOnFailure = true)
{propSetString(property, value, 0, throwOnFailure);}
void propSetDouble(const char* property, double value, bool throwOnFailure = true)
{propSetDouble(property, value, 0, throwOnFailure);}
void propSetInt(const char* property, int value, bool throwOnFailure = true)
{propSetInt(property, value, 0, throwOnFailure);}
/// get a pointer property
void *propGetPointer(const char* property, int idx, bool throwOnFailure = true) const;
/// get a string property
std::string propGetString(const char* property, int idx, bool throwOnFailure = true) const;
/// get a double property
double propGetDouble(const char* property, int idx, bool throwOnFailure = true) const;
/// get an int property
int propGetInt(const char* property, int idx, bool throwOnFailure = true) const;
/// get a pointer property with index 0
void* propGetPointer(const char* property, bool throwOnFailure = true) const
{
return propGetPointer(property, 0, throwOnFailure);
}
/// get a string property with index 0
std::string propGetString(const char* property, bool throwOnFailure = true) const
{
return propGetString(property, 0, throwOnFailure);
}
/// get a double property with index 0
double propGetDouble(const char* property, bool throwOnFailure = true) const
{
return propGetDouble(property, 0, throwOnFailure);
}
/// get an int property with index 0
int propGetInt(const char* property, bool throwOnFailure = true) const
{
return propGetInt(property, 0, throwOnFailure);
}
std::list<std::string> propGetNString(const char* property, bool throwOnFailure = true) const;
};
// forward decl of the image effect
class ImageEffect;
};
// undeclare the protected assign and CC macro
#undef mDeclareProtectedAssignAndCC
#endif
File diff suppressed because it is too large Load Diff
+286
View File
@@ -0,0 +1,286 @@
#ifndef _ofxsInteract_H_
#define _ofxsInteract_H_
// Copyright OpenFX and contributors to the OpenFX project.
// SPDX-License-Identifier: BSD-3-Clause
/** @file This file contains core code that wraps OFX 'objects' with C++ classes.
This file only holds code that is visible to a plugin implementation, and so hides much
of the direct OFX objects and any library side only functions.
*/
#include "ofxsParam.h"
#include <list>
/** @brief Nasty macro used to define empty protected copy ctors and assign ops */
#define mDeclareProtectedAssignAndCC(CLASS) \
CLASS &operator=(const CLASS &) {assert(false); return *this;} \
CLASS(const CLASS &) {assert(false); }
/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries.
*/
namespace OFX {
/** @brief forward declaration */
class ImageEffect;
/// all image effect interacts have these argumens
struct InteractArgs {
/// ctor
InteractArgs(const PropertySet &props);
double time; /**< @brief The current effect time to draw at */
OfxPointD renderScale; /**< @brief The current render scale being applied to any image that would be fetched */
};
/** @brief struct to pass arguments into OFX::Interact::draw */
struct DrawArgs : public InteractArgs {
DrawArgs(const PropertySet &props);
#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4
OfxPointD viewportSize; /**< @brief The openGL viewport size for the instance */
#endif
OfxPointD pixelScale; /**< @brief The current effect time to draw at */
OfxRGBColourD backGroundColour; /**< @brief The current background colour, ignore the A */
};
/** @brief POD to pass arguments into OFX::Interact pen actions */
struct PenArgs : public InteractArgs {
PenArgs(const PropertySet &props);
#ifdef kOfxInteractPropViewportSize // removed in OFX 1.4
OfxPointD viewportSize; /**< @brief The openGL viewport size for the instance */
#endif
OfxPointD pixelScale; /**< @brief The current effect time to draw at */
OfxRGBColourD backGroundColour; /**< @brief The current background colour, ignore the A */
OfxPointD penPosition; /**< @brief The current pen position */
OfxPointD penViewportPosition;/**< @brief The current pen position in viewport coordinates */
double penPressure; /**< @brief The normalised pressure on the pen */
};
/** @brief struct to pass arguments into OFX::Interact key actions
Note
- some keys cannot be represented as UTF8 strings (eg: the key pad page down key kOfxKey_KP_Page_Up), in which case the key string will be set to "".
- some UTF8 symbols (generally non-English language ones) cannot be represented by one of the keySymbols, in which case the UTF8 string will be set to some non empty value, but the keySymbol will be set to kOfxKey_Unknown.
- in no case will keyString be set to "" and keySymbol be set to kOfxKey_Unknown.
*/
struct KeyArgs : public InteractArgs {
KeyArgs(const PropertySet &props);
int keySymbol; /**< @brief The key represented as one of the entries in ofxKeySyms.h, see note in OFX::KeyArgs */
std::string keyString; /**< @brief That key as a UTF8 string, see note in OFX::KeyArgs */
};
/** @brief struct to pass arguments into OFX::Interact focus actions */
struct FocusArgs : public InteractArgs {
FocusArgs(const PropertySet &props);
OfxPointD viewportSize; /**< @brief The openGL viewport size for the instance */
OfxPointD pixelScale; /**< @brief The current effect time to draw at */
OfxRGBColourD backGroundColour; /**< @brief The current background colour, ignore the A */
};
/** @brief Wraps up an OFX interact object for an Image Effect. It won't work for any other plug-in type at present (it would need to be broken into a hierarchy of classes).
*/
class Interact {
protected :
OfxInteractHandle _interactHandle; /**< @brief The handle for this interact */
PropertySet _interactProperties; /**< @brief The property set on this interact */
std::list<Param *> _slaveParams; /**< @brief List of params we are currently slaved to */
ImageEffect *_effect; /**< @brief The instance we are associated with */
public :
/** @brief ctor */
Interact(OfxInteractHandle handle);
/** @brief virtual destructor */
virtual ~Interact();
PropertySet &getProperties() { return _interactProperties; }
/** @brief The bitdepth of each component in the openGL frame buffer */
int getBitDepth(void) const;
/** @brief Does the openGL frame buffer have an alpha */
bool hasAlpha(void) const;
/** @brief Returns the size of a real screen pixel under the interact's cannonical projection */
OfxPointD getPixelScale(void) const;
/** @brief The suggested colour to draw a widget in an interact. Returns false if there is no suggestion. */
bool getSuggestedColour(OfxRGBColourD &c) const;
/** @brief the background colour */
OfxRGBColourD getBackgroundColour(void) const;
/** @brief Set a param that the interact should be redrawn on if its value changes */
void addParamToSlaveTo(Param *p);
/** @brief Remova a param that the interact should be redrawn on if its value changes */
void removeParamToSlaveTo(Param *p);
/** @brief Request a redraw */
void requestRedraw(void) const;
/** @brief Swap a buffer in the case of a double bufferred interact, this is possibly a silly one */
void swapBuffers(void) const;
////////////////////////////////////////////////////////////////////////////////
// override the below in derived classes to do something useful
/** @brief the function called to draw in the interact */
virtual bool draw(const DrawArgs &args);
/** @brief the function called to handle pen motion in the interact
returns true if the interact trapped the action in some sense. This will block the action being passed to
any other interact that may share the viewer.
*/
virtual bool penMotion(const PenArgs &args);
/** @brief the function called to handle pen down events in the interact
returns true if the interact trapped the action in some sense. This will block the action being passed to
any other interact that may share the viewer.
*/
virtual bool penDown(const PenArgs &args);
/** @brief the function called to handle pen up events in the interact
returns true if the interact trapped the action in some sense. This will block the action being passed to
any other interact that may share the viewer.
*/
virtual bool penUp(const PenArgs &args);
/** @brief the function called to handle key down events in the interact
returns true if the interact trapped the action in some sense. This will block the action being passed to
any other interact that may share the viewer.
*/
virtual bool keyDown(const KeyArgs &args);
/** @brief the function called to handle key up events in the interact
returns true if the interact trapped the action in some sense. This will block the action being passed to
any other interact that may share the viewer.
*/
virtual bool keyUp(const KeyArgs &args);
/** @brief the function called to handle key down repeat events in the interact
returns true if the interact trapped the action in some sense. This will block the action being passed to
any other interact that may share the viewer.
*/
virtual bool keyRepeat(const KeyArgs &args);
/** @brief Called when the interact is given input focus */
virtual void gainFocus(const FocusArgs &args);
/** @brief Called when the interact is loses input focus */
virtual void loseFocus(const FocusArgs &args);
};
/** @brief an interact for an image effect overlay */
class OverlayInteract : public Interact {
public :
/** @brief ctor */
OverlayInteract(OfxInteractHandle handle);
/** @brief dtor */
virtual ~OverlayInteract();
};
class InteractDescriptor
{
public:
InteractDescriptor():_props(0) {}
virtual ~InteractDescriptor() {}
void setPropertySet(OFX::PropertySet* props){ _props = props; }
virtual Interact* createInstance(OfxInteractHandle handle, ImageEffect *effect) = 0;
void setHasAlpha();
bool getHasAlpha() const;
void setBitDepth();
int getBitDepth() const;
virtual OfxPluginEntryPoint* getMainEntry() = 0;
virtual void describe() {}
protected:
OFX::PropertySet* _props;
};
typedef InteractDescriptor EffectOverlayDescriptor;
class ParamInteractDescriptor : public InteractDescriptor
{
public:
ParamInteractDescriptor():InteractDescriptor(){}
virtual ~ParamInteractDescriptor() {}
void setInteractSizeAspect(double asp);
void setInteractMinimumSize(int x, int y);
void setInteractPreferredSize(int x, int y);
virtual void setParamName(const std::string& pName) { _paramName = pName; }
protected:
std::string _paramName;
};
class ParamInteract : public Interact
{
public:
ParamInteract(OfxInteractHandle handle, ImageEffect* effect);
virtual ~ParamInteract() {}
double getInteractSizeAspect() const;
OfxPointI getInteractMinimumSize() const;
OfxPointI getInteractPreferredSize() const;
OfxPointI getInteractSize() const;
protected:
ImageEffect* _effect;
};
namespace Private
{
OfxStatus interactMainEntry(const char *actionRaw,
const void *handleRaw,
OfxPropertySetHandle inArgsRaw,
OfxPropertySetHandle outArgsRaw,
InteractDescriptor& desc);
}
template<class DESC>
class InteractMainEntry
{
protected:
static OfxStatus overlayInteractMainEntry(const char *action, const void* handle, OfxPropertySetHandle in, OfxPropertySetHandle out)
{
static DESC desc;
return OFX::Private::interactMainEntry(action, handle, in, out, desc);
}
};
template<class DESC, class INSTANCE>
class DefaultEffectOverlayDescriptor : public EffectOverlayDescriptor, public InteractMainEntry<DESC>
{
public:
Interact* createInstance(OfxInteractHandle handle, ImageEffect *effect) { return new INSTANCE(handle, effect); }
virtual OfxPluginEntryPoint* getMainEntry() { return InteractMainEntry<DESC>::overlayInteractMainEntry; }
};
template<class DESC, class INSTANCE>
class DefaultParamInteractDescriptor : public ParamInteractDescriptor, public InteractMainEntry<DESC>
{
public:
Interact* createInstance(OfxInteractHandle handle, ImageEffect *effect) { return new INSTANCE(handle, effect, _paramNameStatic); }
virtual OfxPluginEntryPoint* getMainEntry() { return InteractMainEntry<DESC>::overlayInteractMainEntry; }
virtual void setParamName(const std::string& pName) { _paramNameStatic = pName; }
protected:
static std::string _paramNameStatic;
};
template<class DESC, class INSTANCE> std::string OFX::DefaultParamInteractDescriptor<DESC, INSTANCE>::_paramNameStatic;
};
#undef mDeclareProtectedAssignAndCC
#endif
+43
View File
@@ -0,0 +1,43 @@
#ifndef _ofxsLog_H_
#define _ofxsLog_H_
// Copyright OpenFX and contributors to the OpenFX project.
// SPDX-License-Identifier: BSD-3-Clause
/** @file This file contains OFX logging header code
*/
/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries.
*/
namespace OFX {
/** @brief this namespace wraps up logging functionality */
namespace Log {
/** @brief Indent it, not MP sane at the moment */
void indent(void);
/** @brief Outdent it, not MP sane at the moment */
void outdent(void);
/** @brief Sets the name of the log file. */
void setFileName(const std::string &value);
/** @brief Opens the log file, returns whether this was sucessful or not. */
bool open(void);
/** @brief Closes the log file. */
void close(void);
/** @brief Prints to the log file. */
void print(const char *format, ...);
/** @brief Prints to the log file only if the condition is true and prepends a warning notice. */
void warning(bool condition, const char *format, ...);
/** @brief Prints to the log file only if the condition is true and prepends an error notice. */
void error(bool condition, const char *format, ...);
};
};
#endif
+45
View File
@@ -0,0 +1,45 @@
#ifndef _ofxsMemory_H_
#define _ofxsMemory_H_
// Copyright OpenFX and contributors to the OpenFX project.
// SPDX-License-Identifier: BSD-3-Clause
/** @file This file contains core code that wraps the ofx memory allocator with C++ functions.
This file only holds code that is visible to a plugin implementation, and so hides much
of the direct OFX objects and any library side only functions.
*/
/** @brief The core 'OFX Support' namespace, used by plugin implementations. All code for these are defined in the common support libraries.
*/
namespace OFX {
// forward declaration of class
class ImageEffect;
/** @brief Namespace for general purpose memory allocation */
namespace Memory {
/** @brief Allocate memory.
\arg \e nBytes - the number of bytes to allocate
\arg \e handle - effect instance to assosciate with this memory allocation, or NULL
This function has the host allocate memory using it's own memory resources
and returns that to the plugin. This memory is distinct to any image memory allocation.
Succeeds or throws std::bad_alloc
*/
void *allocate(size_t nBytes,
ImageEffect *handle = 0);
/** @brief release memory
\arg \e ptr - pointer previously returned by OFX::Memory::allocate
*/
void free(void *ptr) noexcept;
};
};
#endif
+30
View File
@@ -0,0 +1,30 @@
#ifndef _ofxsMessage_H_
#define _ofxsMessage_H_
namespace OFX
{
namespace Message
{
enum MessageReplyEnum
{
eMessageReplyOK,
eMessageReplyYes,
eMessageReplyNo,
eMessageReplyFailed
};
enum MessageTypeEnum
{
eMessageFatal,
eMessageError,
eMessageMessage,
eMessageWarning,
eMessageLog,
eMessageQuestion
};
};
};
#endif
+106
View File
@@ -0,0 +1,106 @@
#ifndef _ofxsMultiThread_H_
#define _ofxsMultiThread_H_
// Copyright OpenFX and contributors to the OpenFX project.
// SPDX-License-Identifier: BSD-3-Clause
/** @file This file contains core code that wraps OFX 'objects' with C++ classes.
This file only holds code that is visible to a plugin implementation, and so hides much
of the direct OFX objects and any library side only functions.
*/
#include "ofxsCore.h"
typedef struct OfxMutex* OfxMutexHandle;
namespace OFX {
/** @brief Multi thread namespace */
namespace MultiThread {
/** @brief Class that wraps up SMP multi-processing */
class Processor {
private :
/** @brief Function to pass to the multi thread suite */
static void staticMultiThreadFunction(unsigned int threadIndex, unsigned int threadMax, void *customArg);
public :
/** @brief ctor */
Processor();
/** @brief dtor */
virtual ~Processor();
/** @brief function that will be called in each thread. ID is from 0..nThreads-1 nThreads are the number of threads it is being run over */
virtual void multiThreadFunction(unsigned int threadID, unsigned int nThreads) = 0;
/** @brief call this to kick off multi threading
The nCPUs is 0, the maximum allowable number of CPUs will be used.
*/
virtual void multiThread(unsigned int nCPUs = 0);
};
/** @brief Has the current thread been spawned from an MP */
bool isSpawnedThread(void);
/** @brief The number of CPUs that can be used for MP-ing */
unsigned int getNumCPUs(void);
/** @brief The index of the current thread. From 0 to numCPUs() - 1 */
unsigned int getThreadIndex(void);
/** @brief An OFX mutex */
class Mutex {
protected :
OfxMutexHandle _handle; /**< @brief The handle */
public :
/** @brief ctor */
Mutex(int lockCount = 0);
/** @brief dtor */
virtual ~Mutex(void);
/** @brief lock it, blocks until lock is gained */
void lock();
/** @brief unlock it */
void unlock();
/** @brief attempt to lock, non-blocking
\brief returns
- true if the lock was achieved
- false if it could not
*/
bool tryLock();
};
/// a class to wrap around a mutex which is exception safe
/// it locks the mutex on construction and unlocks it on destruction
class AutoMutex {
protected :
Mutex &_mutex;
public :
/// ctor, acquires the lock
explicit AutoMutex(Mutex &m)
: _mutex(m)
{
_mutex.lock();
}
/// dtor, releases the lock
virtual ~AutoMutex()
{
_mutex.unlock();
}
};
};
};
#endif
File diff suppressed because it is too large Load Diff
+230
View File
@@ -0,0 +1,230 @@
#ifndef _ofxsProcessing_h_
#define _ofxsProcessing_h_
/*
OFX Support Library, a library that skins the OFX plug-in API with C++ classes.
Copyright (C) 2005 The Open Effects Association Ltd
Author Bruno Nicoletti bruno@thefoundry.co.uk
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name The Open Effects Association Ltd, nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The Open Effects Association Ltd
1 Wardour St
London W1D 6PA
England
*/
#include <cassert>
#include <algorithm>
#include "ofxsImageEffect.h"
#include "ofxsMultiThread.h"
#include "ofxsLog.h"
/** @file This file contains a useful base class that can be used to process images
The code below is not so much a skin on the base OFX classes, but code used in implementing
specific image processing algorithms.
*/
namespace OFX {
////////////////////////////////////////////////////////////////////////////////
// base class to process images with
class ImageProcessor : public OFX::MultiThread::Processor {
protected :
OFX::ImageEffect &_effect; /**< @brief effect to render with */
OFX::Image *_dstImg; /**< @brief image to process into */
OfxRectI _renderWindow; /**< @brief render window to use */
bool _isEnabledOpenCLRender; /**< @brief is OpenCL Render Enabled */
bool _isEnabledCudaRender; /**< @brief is Cuda Render Enabled */
bool _isEnabledMetalRender; /**< @brief is Metal Render Enabled */
void* _pOpenCLCmdQ; /**< @brief OpenCL Command Queue Handle */
void* _pCudaStream; /**< @brief Cuda Stream Handle */
void* _pMetalCmdQ; /**< @brief Metal Command Queue Handle */
public :
/** @brief ctor */
ImageProcessor(OFX::ImageEffect &effect)
: _effect(effect)
, _dstImg(0)
, _isEnabledOpenCLRender(false)
, _isEnabledCudaRender(false)
, _isEnabledMetalRender(false)
, _pOpenCLCmdQ(NULL)
, _pCudaStream(NULL)
, _pMetalCmdQ(NULL)
{
_renderWindow.x1 = _renderWindow.y1 = _renderWindow.x2 = _renderWindow.y2 = 0;
}
/** @brief set the destination image */
void setDstImg(OFX::Image *v) {_dstImg = v; }
/** @brief set OpenCL, CUDA render arguments */
void setGPURenderArgs(const OFX::RenderArguments& args)
{
_isEnabledOpenCLRender = args.isEnabledOpenCLRender;
_isEnabledCudaRender = args.isEnabledCudaRender;
_isEnabledMetalRender = args.isEnabledMetalRender;
if (_isEnabledOpenCLRender)
{
_pOpenCLCmdQ = args.pOpenCLCmdQ;
}
if (_isEnabledCudaRender)
{
_pCudaStream = args.pCudaStream;
}
if (_isEnabledMetalRender)
{
_pMetalCmdQ = args.pMetalCmdQ;
}
}
/** @brief reset the render window */
void setRenderWindow(OfxRectI rect) {_renderWindow = rect;}
/** @brief overridden from OFX::MultiThread::Processor. This function is called once on each SMP thread by the base class */
void multiThreadFunction(unsigned int threadId, unsigned int nThreads)
{
// slice the y range into the number of threads it has
unsigned int dy = _renderWindow.y2 - _renderWindow.y1;
// the following is equivalent to std::ceil(dy/(double)nThreads);
unsigned int h = (dy+nThreads-1)/nThreads;
if (h == 0) {
// there are more threads than lines to process
h = 1;
}
if (threadId * h >= dy) {
// empty render subwindow
return;
}
unsigned int y1 = _renderWindow.y1 + threadId * h;
unsigned int step = (threadId + 1) * h;
unsigned int y2 = _renderWindow.y1 + (step < dy ? step : dy);
OfxRectI win = _renderWindow;
win.y1 = y1; win.y2 = y2;
// and render that thread on each
multiThreadProcessImages(win);
}
/** @brief called before any MP is done */
virtual void preProcess(void) {}
/** @brief this is called by process to actually process images using OpenCL when isEnabledOpenCLRender is true, override in derived classes */
virtual void processImagesOpenCL(void)
{
OFX::Log::print("processImagesOpenCL not implemented");
OFX::throwSuiteStatusException(kOfxStatErrUnsupported);
};
/** @brief this is called by process to actually process images using CUDA when isEnabledCudaRender is true, override in derived classes */
virtual void processImagesCuda(void)
{
OFX::Log::print("processImagesCuda not implemented");
OFX::throwSuiteStatusException(kOfxStatErrUnsupported);
};
/** @brief this is called by process to actually process images using Metal when isEnabledMetalRender is true, override in derived classes */
virtual void processImagesMetal(void)
{
OFX::Log::print("processImagesMetal not implemented");
OFX::throwSuiteStatusException(kOfxStatErrUnsupported);
};
/** @brief this is called by multiThreadFunction to actually process images, override in derived classes */
virtual void multiThreadProcessImages(OfxRectI window)
{
OFX::Log::print("multiThreadProcessImages not implemented");
OFX::throwSuiteStatusException(kOfxStatErrUnsupported);
};
/** @brief called before any MP is done */
virtual void postProcess(void) {}
/** @brief called to process everything */
virtual void process(void)
{
// If _dstImg was set, check that the _renderWindow is lying into dstBounds
if (_dstImg) {
const OfxRectI& dstBounds = _dstImg->getBounds();
// is the renderWindow within dstBounds ?
assert(dstBounds.x1 <= _renderWindow.x1 && _renderWindow.x2 <= dstBounds.x2 &&
dstBounds.y1 <= _renderWindow.y1 && _renderWindow.y2 <= dstBounds.y2);
// exit gracefully in case of error
if (!(dstBounds.x1 <= _renderWindow.x1 && _renderWindow.x2 <= dstBounds.x2 &&
dstBounds.y1 <= _renderWindow.y1 && _renderWindow.y2 <= dstBounds.y2) ||
(_renderWindow.x1 >= _renderWindow.x2) ||
(_renderWindow.y1 >= _renderWindow.y2)) {
return;
}
}
// call the pre MP pass
preProcess();
if (_isEnabledOpenCLRender)
{
OFX::Log::print("processing via OpenCL");
processImagesOpenCL();
}
else if (_isEnabledCudaRender)
{
OFX::Log::print("processing via CUDA");
processImagesCuda();
}
else if (_isEnabledMetalRender)
{
OFX::Log::print("processing via Metal");
processImagesMetal();
}
else // is CPU
{
OFX::Log::print("processing via CPU");
// make sure there are at least 4096 pixels per CPU and at least 1 line par CPU
unsigned int nCPUs = (std::min(_renderWindow.x2 - _renderWindow.x1, 4096) *
(_renderWindow.y2 - _renderWindow.y1)) / 4096;
// make sure the number of CPUs is valid (and use at least 1 CPU)
nCPUs = std::max(1u, std::min(nCPUs, OFX::MultiThread::getNumCPUs()));
// call the base multi threading code, should put a pre & post thread calls in too
multiThread(nCPUs);
}
// call the post MP pass
postProcess();
}
};
};
#endif
+172
View File
@@ -0,0 +1,172 @@
#!/bin/bash
#
# Olive Community Edition - Non-Linear Video Editor
# Copyright (C) 2025 Olive CE Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Package all local libraries into an application or plugin bundle on OSX
#
# Author: Frederic Devernay <frederic.devernay@m4x.org>
#
# This script copies the .so, .la and .xml files needed to redistribute a mac application
# This file is strongly inspired from the osx-app.sh script from the Inkscape source code
#
# In the XCode project, the "Runtime search paths" of your binaries should be set to
# "@loader_path/../Frameworks @loader_path/../Libraries" so that it finds libraries
# and frameworks at runtime.
# If using a Makefile, you should add the following flags at link time:
# -Wl,-rpath,@loader_path/../Frameworks -Wl,-rpath,@loader_path/../Libraries
#
# References:
# http://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html
# http://www.dribin.org/dave/blog/archives/2009/11/15/rpath/
# env LANG=C is necessary so that sed doesn't try to interpret the binary file with a specific encoding
LANG=C
export LANG
if [ $# != 2 ]; then
echo "Usage: $0 AppName.app|Bundle.bundle Executablename"
echo "moves macports and local libraries into AppName.app"
exit 1
fi
MACPORTS=/opt/local
HOMEBREW=/brew2/local
LOCAL=/usr/local
# add to PATH
PATH="$MACPORTS/bin:$HOMEBREW/bin:$LOCAL/bin:$PATH"
if ! port help > /dev/null 2>&1; then
echo "Please make sure that MacPorts is installed in /opt/local"
exit 1
fi
package="$1"
binary="$package/Contents/MacOS/$2"
libdir="Libraries"
pkglib="$package/Contents/$libdir"
if [ ! -x "$binary" ]; then
echo "Error: $binary does not exist or is not an executable"
exit 1
fi
rpath=`otool -l $binary | grep -A 3 LC_RPATH |grep path|awk '{ print $2 }'`
if [[ ! ("$rpath" == *"@loader_path/../Libraries"*) ]]; then
echo "Error:: The runtime search path in $binary does not contain \"@loader_path/../Libraries\". Please set it in your Xcode project, or link the binary with the flags -Xlinker -rpath -Xlinker \"@loader_path/../Libraries\""
exit 1
fi
# Test dirs
test -d "$pkglib" || mkdir "$pkglib"
test -d "$pkglib/share/" || mkdir "$pkglib/share/"
LIBADD=
#############################
# test if ImageMagick is used
if otool -L "$binary" | fgrep libMagick > /dev/null; then
# Check that ImageMagick is properly installed
if ! pkg-config --modversion ImageMagick >/dev/null 2>&1; then
echo "Missing ImageMagick -- please install ImageMagick ('sudo port install ImageMagick +no_x11 +universal') and try again." >&2
exit 1
fi
# Update the ImageMagick path in startup script.
IMAGEMAGICKVER=`pkg-config --modversion ImageMagick`
IMAGEMAGICKMAJ=${IMAGEMAGICKVER%.*.*}
IMAGEMAGICKLIB=`pkg-config --variable=libdir ImageMagick`
IMAGEMAGICKSHARE=`pkg-config --variable=prefix ImageMagick`/share
# if I get this right, sed substitutes in the exe the occurences of IMAGEMAGICKVER
# into the actual value retrieved from the package.
# We don't need this because we use MAGICKCORE_PACKAGE_VERSION declared in the <magick/magick-config.h>
# sed -e "s,IMAGEMAGICKVER,$IMAGEMAGICKVER,g" -i "" $pkgbin/DisparityKillerM
# copy the ImageMagick libraries (.la and .so)
cp -r "$IMAGEMAGICKLIB/ImageMagick-$IMAGEMAGICKVER" "$pkglib/"
cp -r "$IMAGEMAGICKSHARE/ImageMagick-$IMAGEMAGICKMAJ" "$pkglib/share/"
LIBADD="$LIBADD $pkglib/ImageMagick-$IMAGEMAGICKVER/modules-*/*/*.so"
WITH_IMAGEMAGICK=yes
fi
# expand glob patterns in LIBADD
LIBADD=`echo $LIBADD`
# Find out the library dependencies
# (i.e. $LOCAL or $MACPORTS), then loop until no changes.
a=1
nfiles=0
alllibs=""
endl=true
while $endl; do
#echo -e "\033[1mLooking for dependencies.\033[0m Round" $a
libs="`otool -L $pkglib/* $LIBADD $binary 2>/dev/null | fgrep compatibility | cut -d\( -f1 | grep -e $LOCAL'\\|'$HOMEBREW'\\|'$MACPORTS | sort | uniq`"
if [ -n "$libs" ]; then
cp -f $libs $pkglib
alllibs="`ls $alllibs $libs | sort | uniq`"
fi
let "a+=1"
nnfiles=`ls $pkglib | wc -l`
if [ $nnfiles = $nfiles ]; then
endl=false
else
nfiles=$nnfiles
fi
done
# all the libraries were copied, now change the names...
## We use @rpath instead of @executable_path/../$libdir because it's shorter
## than /opt/local, so it always works. The downside is that the XCode project
## has to link the binary with "Runtime search paths" set correctly
## (e.g. to "@loader_path/../Frameworks @loader_path/../Libraries" ).
if [ -n "$alllibs" ]; then
changes=""
for l in $alllibs; do
changes="$changes -change $l @rpath/`basename $l`"
done
for f in $pkglib/* $LIBADD "$binary"; do
# avoid directories
if [ -f $f ]; then
if ! install_name_tool $changes $f; then
echo "Error: 'install_name_tool $changes $f' failed"
exit 1
fi
fi
done
fi
#if [ "$WITH_IMAGEMAGICK" = "yes" ]; then
# and now, obfuscate all the default paths in dynamic libraries
# and ImageMagick modules and config files
# generate a pseudo-random string which has the same length as $MACPORTS
RANDSTR="R7bUU6jiFvqrPy6zLVPwIC3b93R2b1RG2qD3567t8hC3b93R2b1RG2qD3567t8h"
MACRAND=${RANDSTR:0:${#MACPORTS}}
HOMEBREWRAND=${RANDSTR:0:${#HOMEBREW}}
LOCALRAND=${RANDSTR:0:${#LOCAL}}
find $pkglib -type f -exec sed -e "s@$MACPORTS@$MACRAND@g" -e "s@$HOMEBREW@$HOMEBREWRAND@g" -e "s@$LOCAL@$LOCALRAND@g" -i "" {} \;
sed -e "s@$MACPORTS@$MACRAND@g" -e "s@$HOMEBREW@$HOMEBREWRAND@g" -e "s@$LOCAL@$LOCALRAND@g" -i "" "$binary"
#fi