Try to fix plugin issue
This commit is contained in:
@@ -13,6 +13,7 @@ jobs:
|
|||||||
os: [ubuntu-latest, macos-latest, windows-2022]
|
os: [ubuntu-latest, macos-latest, windows-2022]
|
||||||
env:
|
env:
|
||||||
CMAKE_BUILD_TYPE: Release
|
CMAKE_BUILD_TYPE: Release
|
||||||
|
RUN_OFX_ITEST: "0"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -107,6 +108,40 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build --config ${{ env.CMAKE_BUILD_TYPE }}
|
run: cmake --build build --config ${{ env.CMAKE_BUILD_TYPE }}
|
||||||
|
|
||||||
|
- name: Build OpenFX misc plugins (Linux, optional)
|
||||||
|
if: runner.os == 'Linux' && env.RUN_OFX_ITEST == '1'
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 https://github.com/NatronGitHub/openfx-misc.git
|
||||||
|
cmake -S openfx-misc -B openfx-misc/build -G Ninja \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build openfx-misc/build
|
||||||
|
echo "OAK_OFX_ITEST=1" >> "$GITHUB_ENV"
|
||||||
|
echo "OAK_OFX_PLUGIN_PATH=${PWD}/openfx-misc/build" >> "$GITHUB_ENV"
|
||||||
|
echo "OAK_OFX_PLUGIN_ID=net.sf.openfx.ChromaKeyerPlugin" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Build OpenFX misc plugins (macOS, optional)
|
||||||
|
if: runner.os == 'macOS' && env.RUN_OFX_ITEST == '1'
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 https://github.com/NatronGitHub/openfx-misc.git
|
||||||
|
cmake -S openfx-misc -B openfx-misc/build -G Ninja \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build openfx-misc/build
|
||||||
|
echo "OAK_OFX_ITEST=1" >> "$GITHUB_ENV"
|
||||||
|
echo "OAK_OFX_PLUGIN_PATH=${PWD}/openfx-misc/build" >> "$GITHUB_ENV"
|
||||||
|
echo "OAK_OFX_PLUGIN_ID=net.sf.openfx.ChromaKeyerPlugin" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Build OpenFX misc plugins (Windows, optional)
|
||||||
|
if: runner.os == 'Windows' && env.RUN_OFX_ITEST == '1'
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 https://github.com/NatronGitHub/openfx-misc.git
|
||||||
|
cmake -S openfx-misc -B openfx-misc/build -G Ninja `
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build openfx-misc/build
|
||||||
|
"OAK_OFX_ITEST=1" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||||
|
"OAK_OFX_PLUGIN_PATH=$env:GITHUB_WORKSPACE\\openfx-misc\\build" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||||
|
"OAK_OFX_PLUGIN_ID=net.sf.openfx.ChromaKeyerPlugin" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||||
|
|
||||||
- name: Test (Linux)
|
- name: Test (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -162,7 +162,9 @@ AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const PixelFormat &pix_fmt,
|
|||||||
case PixelFormat::U16:
|
case PixelFormat::U16:
|
||||||
return AV_PIX_FMT_RGB48;
|
return AV_PIX_FMT_RGB48;
|
||||||
case PixelFormat::F16:
|
case PixelFormat::F16:
|
||||||
|
return AV_PIX_FMT_RGBF16;
|
||||||
case PixelFormat::F32:
|
case PixelFormat::F32:
|
||||||
|
return AV_PIX_FMT_RGBF32;
|
||||||
case PixelFormat::INVALID:
|
case PixelFormat::INVALID:
|
||||||
case PixelFormat::COUNT:
|
case PixelFormat::COUNT:
|
||||||
break;
|
break;
|
||||||
@@ -174,7 +176,9 @@ AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const PixelFormat &pix_fmt,
|
|||||||
case PixelFormat::U16:
|
case PixelFormat::U16:
|
||||||
return AV_PIX_FMT_RGBA64;
|
return AV_PIX_FMT_RGBA64;
|
||||||
case PixelFormat::F16:
|
case PixelFormat::F16:
|
||||||
|
return AV_PIX_FMT_RGBAF16;
|
||||||
case PixelFormat::F32:
|
case PixelFormat::F32:
|
||||||
|
return AV_PIX_FMT_RGBAF32;
|
||||||
case PixelFormat::INVALID:
|
case PixelFormat::INVALID:
|
||||||
case PixelFormat::COUNT:
|
case PixelFormat::COUNT:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -204,6 +204,25 @@ olive::plugin::OliveClipInstance::getImage(OfxTime time,
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<OFX::Host::ImageEffect::Image>
|
||||||
|
olive::plugin::OliveClipInstance::getOutputImage(OfxTime time)
|
||||||
|
{
|
||||||
|
if (images_.contains(time)) {
|
||||||
|
return images_.value(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
OfxRectD rod_d = getRegionOfDefinition(time);
|
||||||
|
OfxRectI rod = { static_cast<int>(std::floor(rod_d.x1)),
|
||||||
|
static_cast<int>(std::floor(rod_d.y1)),
|
||||||
|
static_cast<int>(std::ceil(rod_d.x2)),
|
||||||
|
static_cast<int>(std::ceil(rod_d.y2)) };
|
||||||
|
OfxRectI bounds = rod;
|
||||||
|
|
||||||
|
auto image = std::make_shared<Image>(*this, params_, bounds, rod, true);
|
||||||
|
images_.insert(time, image);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
OfxRectD
|
OfxRectD
|
||||||
olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const
|
olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const
|
||||||
{
|
{
|
||||||
@@ -231,7 +250,14 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
if (!texture) {
|
if (!texture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->params_ = texture->params();
|
VideoParams incoming = texture->params();
|
||||||
|
if (params_.format() != PixelFormat::INVALID &&
|
||||||
|
params_.channel_count() > 0) {
|
||||||
|
incoming.set_format(params_.format());
|
||||||
|
incoming.set_channel_count(params_.channel_count());
|
||||||
|
incoming.set_premultiplied_alpha(params_.premultiplied_alpha());
|
||||||
|
}
|
||||||
|
this->params_ = incoming;
|
||||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
||||||
input_textures_.insert(time, texture);
|
input_textures_.insert(time, texture);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -44,10 +44,7 @@ public:
|
|||||||
{
|
{
|
||||||
params_ = params;
|
params_ = params;
|
||||||
}
|
}
|
||||||
std::shared_ptr<OFX::Host::ImageEffect::Image> getOutputImage(OfxTime time)
|
std::shared_ptr<OFX::Host::ImageEffect::Image> getOutputImage(OfxTime time);
|
||||||
{
|
|
||||||
return images_[time];
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string &getUnmappedBitDepth() const override;
|
const std::string &getUnmappedBitDepth() const override;
|
||||||
const std::string &getUnmappedComponents() const override;
|
const std::string &getUnmappedComponents() const override;
|
||||||
|
|||||||
@@ -191,6 +191,16 @@ OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id, c
|
|||||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||||
QString message(buffer);
|
QString message(buffer);
|
||||||
|
|
||||||
|
auto *app = qobject_cast<QApplication *>(QCoreApplication::instance());
|
||||||
|
if (!app) {
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "OFX message:" << type << message;
|
||||||
|
if (strcmp(type, kOfxMessageQuestion) == 0) {
|
||||||
|
return kOfxStatReplyNo;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(type, kOfxMessageQuestion) == 0) {
|
if (strcmp(type, kOfxMessageQuestion) == 0) {
|
||||||
auto ret = QMessageBox::question(nullptr, "", message,
|
auto ret = QMessageBox::question(nullptr, "", message,
|
||||||
QMessageBox::Ok, QMessageBox::Cancel);
|
QMessageBox::Ok, QMessageBox::Cancel);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QApplication>
|
||||||
#include <qmessagebox.h>
|
#include <qmessagebox.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
@@ -254,9 +255,6 @@ OFX::Host::Param::Instance *
|
|||||||
OlivePluginInstance::newParam(const std::string &name,
|
OlivePluginInstance::newParam(const std::string &name,
|
||||||
OFX::Host::Param::Descriptor &desc)
|
OFX::Host::Param::Descriptor &desc)
|
||||||
{
|
{
|
||||||
if (!node_) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
const std::string &type = desc.getType();
|
const std::string &type = desc.getType();
|
||||||
|
|
||||||
if (type == kOfxParamTypeInteger) {
|
if (type == kOfxParamTypeInteger) {
|
||||||
@@ -372,6 +370,11 @@ void OlivePluginInstance::progressStart(const std::string &message,
|
|||||||
progress_cancelled_ = false;
|
progress_cancelled_ = false;
|
||||||
progress_active_ = true;
|
progress_active_ = true;
|
||||||
|
|
||||||
|
auto *app = qobject_cast<QApplication *>(QCoreApplication::instance());
|
||||||
|
if (!app) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (progress_dialog_) {
|
if (progress_dialog_) {
|
||||||
progress_dialog_->close();
|
progress_dialog_->close();
|
||||||
progress_dialog_->deleteLater();
|
progress_dialog_->deleteLater();
|
||||||
@@ -482,5 +485,13 @@ OFX::Host::ImageEffect::ClipInstance *OlivePluginInstance::newClipInstance(
|
|||||||
return clipInstance;
|
return clipInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OlivePluginInstance::~OlivePluginInstance()
|
||||||
|
{
|
||||||
|
if (!QCoreApplication::instance() ||
|
||||||
|
qEnvironmentVariableIsSet("OAK_OFX_ITEST")) {
|
||||||
|
_created = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
explicit OlivePluginInstance(Instance & instance):Instance(instance){};
|
explicit OlivePluginInstance(Instance & instance):Instance(instance){};
|
||||||
~OlivePluginInstance() override = default;
|
~OlivePluginInstance() override;
|
||||||
const std::string &getDefaultOutputFielding() const override;
|
const std::string &getDefaultOutputFielding() const override;
|
||||||
|
|
||||||
void setVideoParam(VideoParams params)
|
void setVideoParam(VideoParams params)
|
||||||
@@ -82,6 +82,10 @@ public:
|
|||||||
{
|
{
|
||||||
open_gl_enabled_ = enabled;
|
open_gl_enabled_ = enabled;
|
||||||
}
|
}
|
||||||
|
bool isCreated() const
|
||||||
|
{
|
||||||
|
return _created;
|
||||||
|
}
|
||||||
OFX::Host::ImageEffect::ClipInstance *newClipInstance(
|
OFX::Host::ImageEffect::ClipInstance *newClipInstance(
|
||||||
OFX::Host::ImageEffect::Instance *plugin,
|
OFX::Host::ImageEffect::Instance *plugin,
|
||||||
OFX::Host::ImageEffect::ClipDescriptor *descriptor,
|
OFX::Host::ImageEffect::ClipDescriptor *descriptor,
|
||||||
|
|||||||
@@ -61,12 +61,18 @@ protected:
|
|||||||
std::shared_ptr<PluginNode> _node;
|
std::shared_ptr<PluginNode> _node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
QString id;
|
QString id;
|
||||||
|
bool has_value_ = false;
|
||||||
|
int value_ = 0;
|
||||||
public:
|
public:
|
||||||
IntegerInstance(std::shared_ptr<PluginNode>node, OFX::Host::Param::Descriptor &descriptor)
|
IntegerInstance(std::shared_ptr<PluginNode>node, OFX::Host::Param::Descriptor &descriptor)
|
||||||
: _node(node), _descriptor(descriptor),
|
: _node(node), _descriptor(descriptor),
|
||||||
OFX::Host::Param::IntegerInstance(_descriptor){}
|
OFX::Host::Param::IntegerInstance(_descriptor){}
|
||||||
OfxStatus get(int &a)
|
OfxStatus get(int &a)
|
||||||
{
|
{
|
||||||
|
if (!_node) {
|
||||||
|
a = has_value_ ? value_ : 0;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
if (id.isEmpty()) {
|
if (id.isEmpty()) {
|
||||||
return kOfxStatErrBadHandle;
|
return kOfxStatErrBadHandle;
|
||||||
}
|
}
|
||||||
@@ -81,6 +87,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time, int &data)
|
OfxStatus get(OfxTime time, int &data)
|
||||||
{
|
{
|
||||||
|
if (!_node) {
|
||||||
|
data = has_value_ ? value_ : 0;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
if (id.isEmpty()) {
|
if (id.isEmpty()) {
|
||||||
return kOfxStatErrBadHandle;
|
return kOfxStatErrBadHandle;
|
||||||
}
|
}
|
||||||
@@ -94,6 +104,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(int data)
|
OfxStatus set(int data)
|
||||||
{
|
{
|
||||||
|
if (!_node) {
|
||||||
|
value_ = data;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kInt, data);
|
NodeValue::kInt, data);
|
||||||
|
|
||||||
@@ -105,6 +120,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time, int data)
|
OfxStatus set(OfxTime time, int data)
|
||||||
{
|
{
|
||||||
|
if (!_node) {
|
||||||
|
value_ = data;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
Node::SetValueAtTime(
|
Node::SetValueAtTime(
|
||||||
NodeInput(_node.get(), _descriptor.getName().c_str()),
|
NodeInput(_node.get(), _descriptor.getName().c_str()),
|
||||||
@@ -119,6 +139,8 @@ class DoubleInstance : public OFX::Host::Param::DoubleInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
double value_ = 0.0;
|
||||||
public:
|
public:
|
||||||
DoubleInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
DoubleInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
||||||
: OFX::Host::Param::DoubleInstance(descriptor)
|
: OFX::Host::Param::DoubleInstance(descriptor)
|
||||||
@@ -129,6 +151,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(double& data)
|
OfxStatus get(double& data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : 0.0;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<double>()) {
|
if (variant.canConvert<double>()) {
|
||||||
data = variant.toDouble();
|
data = variant.toDouble();
|
||||||
@@ -139,6 +165,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time, double& data)
|
OfxStatus get(OfxTime time, double& data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : 0.0;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant =
|
QVariant variant =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
@@ -151,6 +181,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(double data)
|
OfxStatus set(double data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kFloat, data);
|
NodeValue::kFloat, data);
|
||||||
auto command = new NodeParamSetSplitStandardValueCommand(
|
auto command = new NodeParamSetSplitStandardValueCommand(
|
||||||
@@ -160,6 +195,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time, double data)
|
OfxStatus set(OfxTime time, double data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
Node::SetValueAtTime(
|
Node::SetValueAtTime(
|
||||||
NodeInput(node.get(), _descriptor.getName().c_str()),
|
NodeInput(node.get(), _descriptor.getName().c_str()),
|
||||||
@@ -181,6 +221,8 @@ class BooleanInstance : public OFX::Host::Param::BooleanInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
bool value_ = false;
|
||||||
public:
|
public:
|
||||||
BooleanInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
BooleanInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
||||||
: OFX::Host::Param::BooleanInstance(descriptor)
|
: OFX::Host::Param::BooleanInstance(descriptor)
|
||||||
@@ -191,6 +233,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(bool& data)
|
OfxStatus get(bool& data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : false;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<bool>()) {
|
if (variant.canConvert<bool>()) {
|
||||||
data = variant.toBool();
|
data = variant.toBool();
|
||||||
@@ -201,6 +247,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time, bool& data)
|
OfxStatus get(OfxTime time, bool& data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : false;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant =
|
QVariant variant =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
@@ -213,6 +263,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(bool data)
|
OfxStatus set(bool data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kBoolean, data);
|
NodeValue::kBoolean, data);
|
||||||
auto command = new NodeParamSetSplitStandardValueCommand(
|
auto command = new NodeParamSetSplitStandardValueCommand(
|
||||||
@@ -222,6 +277,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time, bool data)
|
OfxStatus set(OfxTime time, bool data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
Node::SetValueAtTime(
|
Node::SetValueAtTime(
|
||||||
NodeInput(node.get(), _descriptor.getName().c_str()),
|
NodeInput(node.get(), _descriptor.getName().c_str()),
|
||||||
@@ -235,6 +295,8 @@ class ChoiceInstance : public OFX::Host::Param::ChoiceInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
int value_ = 0;
|
||||||
public:
|
public:
|
||||||
ChoiceInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
ChoiceInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
||||||
: OFX::Host::Param::ChoiceInstance(descriptor)
|
: OFX::Host::Param::ChoiceInstance(descriptor)
|
||||||
@@ -245,6 +307,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(int& data)
|
OfxStatus get(int& data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : 0;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<int>()) {
|
if (variant.canConvert<int>()) {
|
||||||
data = variant.toInt();
|
data = variant.toInt();
|
||||||
@@ -255,6 +321,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time, int& data)
|
OfxStatus get(OfxTime time, int& data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : 0;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant =
|
QVariant variant =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
@@ -267,6 +337,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(int data)
|
OfxStatus set(int data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kCombo, data);
|
NodeValue::kCombo, data);
|
||||||
auto command = new NodeParamSetSplitStandardValueCommand(
|
auto command = new NodeParamSetSplitStandardValueCommand(
|
||||||
@@ -276,6 +351,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time, int data)
|
OfxStatus set(OfxTime time, int data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
Node::SetValueAtTime(
|
Node::SetValueAtTime(
|
||||||
NodeInput(node.get(), _descriptor.getName().c_str()),
|
NodeInput(node.get(), _descriptor.getName().c_str()),
|
||||||
@@ -289,6 +369,8 @@ class RGBAInstance : public OFX::Host::Param::RGBAInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
double value_[4] = {0.0, 0.0, 0.0, 0.0};
|
||||||
public:
|
public:
|
||||||
RGBAInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
RGBAInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
||||||
: OFX::Host::Param::RGBAInstance(descriptor)
|
: OFX::Host::Param::RGBAInstance(descriptor)
|
||||||
@@ -299,6 +381,17 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(double& r,double& g,double& b,double& a)
|
OfxStatus get(double& r,double& g,double& b,double& a)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
r = value_[0];
|
||||||
|
g = value_[1];
|
||||||
|
b = value_[2];
|
||||||
|
a = value_[3];
|
||||||
|
} else {
|
||||||
|
r = g = b = a = 0.0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
olive::core::Color c =
|
olive::core::Color c =
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
.value<olive::core::Color>();
|
.value<olive::core::Color>();
|
||||||
@@ -311,6 +404,17 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time, double& r,double& g,double& b,double& a)
|
OfxStatus get(OfxTime time, double& r,double& g,double& b,double& a)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
r = value_[0];
|
||||||
|
g = value_[1];
|
||||||
|
b = value_[2];
|
||||||
|
a = value_[3];
|
||||||
|
} else {
|
||||||
|
r = g = b = a = 0.0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
olive::core::Color c =
|
olive::core::Color c =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
@@ -324,6 +428,14 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(double r,double g,double b,double a)
|
OfxStatus set(double r,double g,double b,double a)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = r;
|
||||||
|
value_[1] = g;
|
||||||
|
value_[2] = b;
|
||||||
|
value_[3] = a;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kColor,
|
NodeValue::kColor,
|
||||||
QVariant::fromValue(olive::core::Color(r, g, b, a)));
|
QVariant::fromValue(olive::core::Color(r, g, b, a)));
|
||||||
@@ -334,6 +446,14 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time, double r,double g,double b,double a)
|
OfxStatus set(OfxTime time, double r,double g,double b,double a)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = r;
|
||||||
|
value_[1] = g;
|
||||||
|
value_[2] = b;
|
||||||
|
value_[3] = a;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
||||||
@@ -354,6 +474,8 @@ class RGBInstance : public OFX::Host::Param::RGBInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
double value_[3] = {0.0, 0.0, 0.0};
|
||||||
public:
|
public:
|
||||||
RGBInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
RGBInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
||||||
: OFX::Host::Param::RGBInstance(descriptor)
|
: OFX::Host::Param::RGBInstance(descriptor)
|
||||||
@@ -364,6 +486,16 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(double& r,double& g,double& b)
|
OfxStatus get(double& r,double& g,double& b)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
r = value_[0];
|
||||||
|
g = value_[1];
|
||||||
|
b = value_[2];
|
||||||
|
} else {
|
||||||
|
r = g = b = 0.0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
olive::core::Color c =
|
olive::core::Color c =
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
.value<olive::core::Color>();
|
.value<olive::core::Color>();
|
||||||
@@ -375,6 +507,16 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time, double& r,double& g,double& b)
|
OfxStatus get(OfxTime time, double& r,double& g,double& b)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
r = value_[0];
|
||||||
|
g = value_[1];
|
||||||
|
b = value_[2];
|
||||||
|
} else {
|
||||||
|
r = g = b = 0.0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
olive::core::Color c =
|
olive::core::Color c =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
@@ -387,6 +529,13 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(double r,double g,double b)
|
OfxStatus set(double r,double g,double b)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = r;
|
||||||
|
value_[1] = g;
|
||||||
|
value_[2] = b;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kColor,
|
NodeValue::kColor,
|
||||||
QVariant::fromValue(olive::core::Color(r, g, b)));
|
QVariant::fromValue(olive::core::Color(r, g, b)));
|
||||||
@@ -397,6 +546,13 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time, double r,double g,double b)
|
OfxStatus set(OfxTime time, double r,double g,double b)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = r;
|
||||||
|
value_[1] = g;
|
||||||
|
value_[2] = b;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
||||||
@@ -414,6 +570,8 @@ class Double2DInstance : public OFX::Host::Param::Double2DInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
double value_[2] = {0.0, 0.0};
|
||||||
public:
|
public:
|
||||||
Double2DInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
Double2DInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
||||||
: OFX::Host::Param::Double2DInstance(descriptor)
|
: OFX::Host::Param::Double2DInstance(descriptor)
|
||||||
@@ -424,6 +582,15 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(double& x,double& y)
|
OfxStatus get(double& x,double& y)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
x = value_[0];
|
||||||
|
y = value_[1];
|
||||||
|
} else {
|
||||||
|
x = y = 0.0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVector2D vec =
|
QVector2D vec =
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
.value<QVector2D>();
|
.value<QVector2D>();
|
||||||
@@ -433,6 +600,15 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time,double& x,double& y)
|
OfxStatus get(OfxTime time,double& x,double& y)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
x = value_[0];
|
||||||
|
y = value_[1];
|
||||||
|
} else {
|
||||||
|
x = y = 0.0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVector2D vec =
|
QVector2D vec =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
@@ -443,6 +619,12 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(double x,double y)
|
OfxStatus set(double x,double y)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = x;
|
||||||
|
value_[1] = y;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kVec2, QVector2D(x, y));
|
NodeValue::kVec2, QVector2D(x, y));
|
||||||
auto command = new NodeParamSetSplitStandardValueCommand(
|
auto command = new NodeParamSetSplitStandardValueCommand(
|
||||||
@@ -452,6 +634,12 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time,double x,double y)
|
OfxStatus set(OfxTime time,double x,double y)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = x;
|
||||||
|
value_[1] = y;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
||||||
@@ -467,6 +655,8 @@ class Integer2DInstance : public OFX::Host::Param::Integer2DInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
int value_[2] = {0, 0};
|
||||||
public:
|
public:
|
||||||
Integer2DInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
Integer2DInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
|
||||||
: OFX::Host::Param::Integer2DInstance(descriptor)
|
: OFX::Host::Param::Integer2DInstance(descriptor)
|
||||||
@@ -477,6 +667,15 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(int& x,int& y)
|
OfxStatus get(int& x,int& y)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
x = value_[0];
|
||||||
|
y = value_[1];
|
||||||
|
} else {
|
||||||
|
x = y = 0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVector2D vec =
|
QVector2D vec =
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
.value<QVector2D>();
|
.value<QVector2D>();
|
||||||
@@ -486,6 +685,15 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time,int& x,int& y)
|
OfxStatus get(OfxTime time,int& x,int& y)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
x = value_[0];
|
||||||
|
y = value_[1];
|
||||||
|
} else {
|
||||||
|
x = y = 0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVector2D vec =
|
QVector2D vec =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
@@ -496,6 +704,12 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(int x,int y)
|
OfxStatus set(int x,int y)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = x;
|
||||||
|
value_[1] = y;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kVec2, QVector2D(x, y));
|
NodeValue::kVec2, QVector2D(x, y));
|
||||||
auto command = new NodeParamSetSplitStandardValueCommand(
|
auto command = new NodeParamSetSplitStandardValueCommand(
|
||||||
@@ -505,6 +719,12 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time,int x,int y)
|
OfxStatus set(OfxTime time,int x,int y)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = x;
|
||||||
|
value_[1] = y;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
Node::SetValueAtTime(NodeInput(node.get(), name), rational::fromDouble(time),
|
||||||
@@ -520,6 +740,8 @@ class Double3DInstance : public OFX::Host::Param::Double3DInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
double value_[3] = {0.0, 0.0, 0.0};
|
||||||
public:
|
public:
|
||||||
Double3DInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
Double3DInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
||||||
OFX::Host::Param::Descriptor& descriptor)
|
OFX::Host::Param::Descriptor& descriptor)
|
||||||
@@ -531,6 +753,16 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(double& x,double& y,double& z)
|
OfxStatus get(double& x,double& y,double& z)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
x = value_[0];
|
||||||
|
y = value_[1];
|
||||||
|
z = value_[2];
|
||||||
|
} else {
|
||||||
|
x = y = z = 0.0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVector3D vec =
|
QVector3D vec =
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
.value<QVector3D>();
|
.value<QVector3D>();
|
||||||
@@ -541,6 +773,16 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time,double& x,double& y,double& z)
|
OfxStatus get(OfxTime time,double& x,double& y,double& z)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
x = value_[0];
|
||||||
|
y = value_[1];
|
||||||
|
z = value_[2];
|
||||||
|
} else {
|
||||||
|
x = y = z = 0.0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVector3D vec =
|
QVector3D vec =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
@@ -552,6 +794,13 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(double x,double y,double z)
|
OfxStatus set(double x,double y,double z)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = x;
|
||||||
|
value_[1] = y;
|
||||||
|
value_[2] = z;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kVec3, QVector3D(x, y, z));
|
NodeValue::kVec3, QVector3D(x, y, z));
|
||||||
auto command = new NodeParamSetSplitStandardValueCommand(
|
auto command = new NodeParamSetSplitStandardValueCommand(
|
||||||
@@ -561,6 +810,13 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time,double x,double y,double z)
|
OfxStatus set(OfxTime time,double x,double y,double z)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = x;
|
||||||
|
value_[1] = y;
|
||||||
|
value_[2] = z;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
@@ -578,6 +834,8 @@ class Integer3DInstance : public OFX::Host::Param::Integer3DInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
int value_[3] = {0, 0, 0};
|
||||||
public:
|
public:
|
||||||
Integer3DInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
Integer3DInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
||||||
OFX::Host::Param::Descriptor& descriptor)
|
OFX::Host::Param::Descriptor& descriptor)
|
||||||
@@ -589,6 +847,16 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(int& x,int& y,int& z)
|
OfxStatus get(int& x,int& y,int& z)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
x = value_[0];
|
||||||
|
y = value_[1];
|
||||||
|
z = value_[2];
|
||||||
|
} else {
|
||||||
|
x = y = z = 0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVector3D vec =
|
QVector3D vec =
|
||||||
node->GetStandardValue(_descriptor.getName().c_str())
|
node->GetStandardValue(_descriptor.getName().c_str())
|
||||||
.value<QVector3D>();
|
.value<QVector3D>();
|
||||||
@@ -599,6 +867,16 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time,int& x,int& y,int& z)
|
OfxStatus get(OfxTime time,int& x,int& y,int& z)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
if (has_value_) {
|
||||||
|
x = value_[0];
|
||||||
|
y = value_[1];
|
||||||
|
z = value_[2];
|
||||||
|
} else {
|
||||||
|
x = y = z = 0;
|
||||||
|
}
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVector3D vec =
|
QVector3D vec =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time))
|
rational::fromDouble(time))
|
||||||
@@ -610,6 +888,13 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(int x,int y,int z)
|
OfxStatus set(int x,int y,int z)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = x;
|
||||||
|
value_[1] = y;
|
||||||
|
value_[2] = z;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kVec3, QVector3D(x, y, z));
|
NodeValue::kVec3, QVector3D(x, y, z));
|
||||||
auto command = new NodeParamSetSplitStandardValueCommand(
|
auto command = new NodeParamSetSplitStandardValueCommand(
|
||||||
@@ -619,6 +904,13 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time,int x,int y,int z)
|
OfxStatus set(OfxTime time,int x,int y,int z)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_[0] = x;
|
||||||
|
value_[1] = y;
|
||||||
|
value_[2] = z;
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
const QString name = _descriptor.getName().c_str();
|
const QString name = _descriptor.getName().c_str();
|
||||||
Node::SetValueAtTime(NodeInput(node.get(), name),
|
Node::SetValueAtTime(NodeInput(node.get(), name),
|
||||||
@@ -636,6 +928,8 @@ class StringInstance : public OFX::Host::Param::StringInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
std::string value_;
|
||||||
public:
|
public:
|
||||||
StringInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
StringInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
||||||
OFX::Host::Param::Descriptor& descriptor)
|
OFX::Host::Param::Descriptor& descriptor)
|
||||||
@@ -647,6 +941,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(std::string &data)
|
OfxStatus get(std::string &data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : std::string();
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<QString>()) {
|
if (variant.canConvert<QString>()) {
|
||||||
data = variant.toString().toStdString();
|
data = variant.toString().toStdString();
|
||||||
@@ -657,6 +955,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time, std::string &data)
|
OfxStatus get(OfxTime time, std::string &data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : std::string();
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant =
|
QVariant variant =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
@@ -669,6 +971,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(const char *data)
|
OfxStatus set(const char *data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data ? data : "";
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QString v = QString::fromUtf8(data);
|
QString v = QString::fromUtf8(data);
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kText, v);
|
NodeValue::kText, v);
|
||||||
@@ -679,6 +986,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time, const char *data)
|
OfxStatus set(OfxTime time, const char *data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data ? data : "";
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
Node::SetValueAtTime(
|
Node::SetValueAtTime(
|
||||||
NodeInput(node.get(), _descriptor.getName().c_str()),
|
NodeInput(node.get(), _descriptor.getName().c_str()),
|
||||||
@@ -692,6 +1004,8 @@ class CustomInstance : public OFX::Host::Param::CustomInstance {
|
|||||||
protected:
|
protected:
|
||||||
std::shared_ptr<PluginNode> node;
|
std::shared_ptr<PluginNode> node;
|
||||||
OFX::Host::Param::Descriptor& _descriptor;
|
OFX::Host::Param::Descriptor& _descriptor;
|
||||||
|
bool has_value_ = false;
|
||||||
|
std::string value_;
|
||||||
public:
|
public:
|
||||||
CustomInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
CustomInstance(std::shared_ptr<PluginNode> effect, const std::string& name,
|
||||||
OFX::Host::Param::Descriptor& descriptor)
|
OFX::Host::Param::Descriptor& descriptor)
|
||||||
@@ -703,6 +1017,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(std::string &data)
|
OfxStatus get(std::string &data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : std::string();
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
QVariant variant = node->GetStandardValue(_descriptor.getName().c_str());
|
||||||
if (variant.canConvert<QByteArray>()) {
|
if (variant.canConvert<QByteArray>()) {
|
||||||
data = variant.toByteArray().toStdString();
|
data = variant.toByteArray().toStdString();
|
||||||
@@ -717,6 +1035,10 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus get(OfxTime time, std::string &data)
|
OfxStatus get(OfxTime time, std::string &data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
data = has_value_ ? value_ : std::string();
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QVariant variant =
|
QVariant variant =
|
||||||
node->GetValueAtTime(_descriptor.getName().c_str(),
|
node->GetValueAtTime(_descriptor.getName().c_str(),
|
||||||
rational::fromDouble(time));
|
rational::fromDouble(time));
|
||||||
@@ -733,6 +1055,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(const char *data)
|
OfxStatus set(const char *data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data ? data : "";
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
QByteArray v = QByteArray(data);
|
QByteArray v = QByteArray(data);
|
||||||
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
SplitValue split = NodeValue::split_normal_value_into_track_values(
|
||||||
NodeValue::kBinary, v);
|
NodeValue::kBinary, v);
|
||||||
@@ -743,6 +1070,11 @@ public:
|
|||||||
}
|
}
|
||||||
OfxStatus set(OfxTime time, const char *data)
|
OfxStatus set(OfxTime time, const char *data)
|
||||||
{
|
{
|
||||||
|
if (!node) {
|
||||||
|
value_ = data ? data : "";
|
||||||
|
has_value_ = true;
|
||||||
|
return kOfxStatOK;
|
||||||
|
}
|
||||||
auto command = new MultiUndoCommand();
|
auto command = new MultiUndoCommand();
|
||||||
Node::SetValueAtTime(
|
Node::SetValueAtTime(
|
||||||
NodeInput(node.get(), _descriptor.getName().c_str()),
|
NodeInput(node.get(), _descriptor.getName().c_str()),
|
||||||
|
|||||||
@@ -23,12 +23,14 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
|
#include <QDebug>
|
||||||
#define GL_PREAMBLE //QMutexLocker __l(&global_opengl_mutex);
|
#define GL_PREAMBLE //QMutexLocker __l(&global_opengl_mutex);
|
||||||
#include "pluginrenderer.h"
|
#include "pluginrenderer.h"
|
||||||
#include "pluginSupport/OliveClip.h"
|
#include "pluginSupport/OliveClip.h"
|
||||||
#include "pluginSupport/OlivePluginInstance.h"
|
#include "pluginSupport/OlivePluginInstance.h"
|
||||||
#include "common/ffmpegutils.h"
|
#include "common/ffmpegutils.h"
|
||||||
#include "ofxImageEffect.h"
|
#include "ofxImageEffect.h"
|
||||||
|
#include "ofxhUtilities.h"
|
||||||
extern "C"{
|
extern "C"{
|
||||||
#include <libavutil/pixfmt.h>
|
#include <libavutil/pixfmt.h>
|
||||||
#include <libavutil/pixdesc.h>
|
#include <libavutil/pixdesc.h>
|
||||||
@@ -67,6 +69,10 @@ static AVPixelFormat GetOfxAVPixelFormat(const OFX::Host::ImageEffect::Image &im
|
|||||||
pix_fmt = AV_PIX_FMT_GRAY8;
|
pix_fmt = AV_PIX_FMT_GRAY8;
|
||||||
} else if (pixel_format == olive::core::PixelFormat::U16) {
|
} else if (pixel_format == olive::core::PixelFormat::U16) {
|
||||||
pix_fmt = AV_PIX_FMT_GRAY16LE;
|
pix_fmt = AV_PIX_FMT_GRAY16LE;
|
||||||
|
} else if (pixel_format == olive::core::PixelFormat::F16) {
|
||||||
|
pix_fmt = AV_PIX_FMT_GRAYF16;
|
||||||
|
} else if (pixel_format == olive::core::PixelFormat::F32) {
|
||||||
|
pix_fmt = AV_PIX_FMT_GRAYF32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +94,109 @@ static AVPixelFormat GetOfxAVPixelFormat(const OFX::Host::ImageEffect::Image &im
|
|||||||
return pix_fmt;
|
return pix_fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AVPixelFormat GetDestinationAVPixelFormat(const olive::VideoParams ¶ms);
|
||||||
|
|
||||||
|
static bool ApplyClipPreferencesToParams(
|
||||||
|
const OFX::Host::ImageEffect::ClipInstance &clip,
|
||||||
|
olive::VideoParams *params)
|
||||||
|
{
|
||||||
|
if (!params) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
olive::core::PixelFormat format = olive::core::PixelFormat::INVALID;
|
||||||
|
const std::string &depth = clip.getPixelDepth();
|
||||||
|
if (depth == kOfxBitDepthByte) {
|
||||||
|
format = olive::core::PixelFormat::U8;
|
||||||
|
} else if (depth == kOfxBitDepthShort) {
|
||||||
|
format = olive::core::PixelFormat::U16;
|
||||||
|
} else if (depth == kOfxBitDepthHalf) {
|
||||||
|
format = olive::core::PixelFormat::F16;
|
||||||
|
} else if (depth == kOfxBitDepthFloat) {
|
||||||
|
format = olive::core::PixelFormat::F32;
|
||||||
|
}
|
||||||
|
|
||||||
|
int channels = 0;
|
||||||
|
const std::string &components = clip.getComponents();
|
||||||
|
if (components == kOfxImageComponentRGBA) {
|
||||||
|
channels = 4;
|
||||||
|
} else if (components == kOfxImageComponentRGB) {
|
||||||
|
channels = 3;
|
||||||
|
} else if (components == kOfxImageComponentAlpha) {
|
||||||
|
channels = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == olive::core::PixelFormat::INVALID || channels == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
params->set_format(format);
|
||||||
|
params->set_channel_count(channels);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static olive::AVFramePtr create_avframe_from_ofx_image(OFX::Host::ImageEffect::Image &image)
|
static olive::AVFramePtr create_avframe_from_ofx_image(OFX::Host::ImageEffect::Image &image)
|
||||||
|
{
|
||||||
|
void *data_ptr = image.getPointerProperty(kOfxImagePropData);
|
||||||
|
if (!data_ptr) {
|
||||||
|
qWarning().noquote() << "OFX output image missing data pointer";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bounds[4] = {0, 0, 0, 0};
|
||||||
|
image.getIntPropertyN(kOfxImagePropBounds, bounds, 4);
|
||||||
|
int width = bounds[2] - bounds[0];
|
||||||
|
int height = bounds[3] - bounds[1];
|
||||||
|
if (width <= 0 || height <= 0) {
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "OFX output image has invalid bounds"
|
||||||
|
<< bounds[0] << bounds[1] << bounds[2] << bounds[3];
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytes_per_pixel = 0;
|
||||||
|
AVPixelFormat pix_fmt = GetOfxAVPixelFormat(image, &bytes_per_pixel);
|
||||||
|
if (pix_fmt == AV_PIX_FMT_NONE || bytes_per_pixel <= 0) {
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "OFX output image has unsupported pixel format depth="
|
||||||
|
<< QString::fromStdString(image.getStringProperty(
|
||||||
|
kOfxImageEffectPropPixelDepth))
|
||||||
|
<< "components="
|
||||||
|
<< QString::fromStdString(
|
||||||
|
image.getStringProperty(kOfxImageEffectPropComponents));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int row_bytes = image.getIntProperty(kOfxImagePropRowBytes);
|
||||||
|
if (row_bytes <= 0) {
|
||||||
|
row_bytes = width * bytes_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *src = static_cast<uint8_t *>(data_ptr);
|
||||||
|
src += bounds[1] * row_bytes + bounds[0] * bytes_per_pixel;
|
||||||
|
|
||||||
|
olive::AVFramePtr frame = olive::CreateAVFramePtr();
|
||||||
|
frame->width = width;
|
||||||
|
frame->height = height;
|
||||||
|
frame->format = pix_fmt;
|
||||||
|
|
||||||
|
if (av_frame_get_buffer(frame.get(), 0) < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int copy_bytes = width * bytes_per_pixel;
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
|
std::memcpy(frame->data[0] + y * frame->linesize[0],
|
||||||
|
src + y * row_bytes,
|
||||||
|
copy_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
static olive::AVFramePtr create_avframe_from_ofx_image_with_params(
|
||||||
|
OFX::Host::ImageEffect::Image &image,
|
||||||
|
const olive::VideoParams ¶ms)
|
||||||
{
|
{
|
||||||
void *data_ptr = image.getPointerProperty(kOfxImagePropData);
|
void *data_ptr = image.getPointerProperty(kOfxImagePropData);
|
||||||
if (!data_ptr) {
|
if (!data_ptr) {
|
||||||
@@ -103,9 +211,14 @@ static olive::AVFramePtr create_avframe_from_ofx_image(OFX::Host::ImageEffect::I
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bytes_per_pixel = 0;
|
AVPixelFormat pix_fmt = GetDestinationAVPixelFormat(params);
|
||||||
AVPixelFormat pix_fmt = GetOfxAVPixelFormat(image, &bytes_per_pixel);
|
if (pix_fmt == AV_PIX_FMT_NONE) {
|
||||||
if (pix_fmt == AV_PIX_FMT_NONE || bytes_per_pixel <= 0) {
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int bytes_per_pixel =
|
||||||
|
params.channel_count() * params.format().byte_count();
|
||||||
|
if (bytes_per_pixel <= 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +259,10 @@ static AVPixelFormat GetDestinationAVPixelFormat(const olive::VideoParams ¶m
|
|||||||
pix_fmt = AV_PIX_FMT_GRAY8;
|
pix_fmt = AV_PIX_FMT_GRAY8;
|
||||||
} else if (params.format() == olive::core::PixelFormat::U16) {
|
} else if (params.format() == olive::core::PixelFormat::U16) {
|
||||||
pix_fmt = AV_PIX_FMT_GRAY16LE;
|
pix_fmt = AV_PIX_FMT_GRAY16LE;
|
||||||
|
} else if (params.format() == olive::core::PixelFormat::F16) {
|
||||||
|
pix_fmt = AV_PIX_FMT_GRAYF16;
|
||||||
|
} else if (params.format() == olive::core::PixelFormat::F32) {
|
||||||
|
pix_fmt = AV_PIX_FMT_GRAYF32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pix_fmt;
|
return pix_fmt;
|
||||||
@@ -280,6 +397,48 @@ static olive::AVFramePtr ConvertFrameIfNeeded(olive::AVFramePtr src,
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int LinesizeToPixels(const olive::VideoParams ¶ms, int linesize_bytes)
|
||||||
|
{
|
||||||
|
const int bytes_per_pixel =
|
||||||
|
params.channel_count() * params.format().byte_count();
|
||||||
|
if (bytes_per_pixel <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return linesize_bytes / bytes_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString PluginIdForInstance(const OFX::Host::ImageEffect::Instance *instance)
|
||||||
|
{
|
||||||
|
if (!instance) {
|
||||||
|
return QStringLiteral("<null>");
|
||||||
|
}
|
||||||
|
auto *plugin = instance->getPlugin();
|
||||||
|
if (!plugin) {
|
||||||
|
return QStringLiteral("<unknown>");
|
||||||
|
}
|
||||||
|
return QString::fromStdString(plugin->getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogOfxFailure(const char *action, OfxStatus stat,
|
||||||
|
const OFX::Host::ImageEffect::Instance *instance)
|
||||||
|
{
|
||||||
|
if (stat == kOfxStatOK || stat == kOfxStatReplyDefault) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "OFX action failed:" << action
|
||||||
|
<< "plugin=" << PluginIdForInstance(instance)
|
||||||
|
<< "status=" << OFX::StatStr(stat)
|
||||||
|
<< "(" << stat << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MarkRenderFailure(olive::Texture *destination)
|
||||||
|
{
|
||||||
|
if (destination && destination->renderer()) {
|
||||||
|
destination->renderer()->ClearDestination(destination, 1.0, 0.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::PluginJob& job,
|
void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::PluginJob& job,
|
||||||
olive::Texture *destination,
|
olive::Texture *destination,
|
||||||
olive::VideoParams destination_params,
|
olive::VideoParams destination_params,
|
||||||
@@ -295,6 +454,7 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
destination && destination->renderer() && destination->id().isValid();
|
destination && destination->renderer() && destination->id().isValid();
|
||||||
if (olive_instance) {
|
if (olive_instance) {
|
||||||
olive_instance->setOpenGLEnabled(use_opengl);
|
olive_instance->setOpenGLEnabled(use_opengl);
|
||||||
|
olive_instance->setVideoParam(destination_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// current render scale of 1
|
// current render scale of 1
|
||||||
@@ -330,36 +490,40 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
}
|
}
|
||||||
clip->setParams(destination_params);
|
clip->setParams(destination_params);
|
||||||
|
|
||||||
OfxStatus stat;
|
OfxStatus stat = kOfxStatOK;
|
||||||
stat = instance->createInstanceAction();
|
if (olive_instance && !olive_instance->isCreated()) {
|
||||||
if(stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
stat = instance->createInstanceAction();
|
||||||
return;
|
if(stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||||
|
LogOfxFailure("createInstance", stat, instance);
|
||||||
|
MarkRenderFailure(destination);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call get region of interest on each of the inputs
|
// call get region of interest on each of the inputs
|
||||||
OfxTime frame = 0;
|
OfxTime frame = 0;
|
||||||
|
|
||||||
clip->setRegionOfDefinition(regionOfDefinition, frame);
|
|
||||||
clip->setOutputTexture(destination, frame);
|
|
||||||
|
|
||||||
const NodeValueRow &values = job.GetValues();
|
const NodeValueRow &values = job.GetValues();
|
||||||
const auto &clips = instance->getDescriptor().getClips();
|
const auto &clips = instance->getDescriptor().getClips();
|
||||||
|
std::map<std::string, TexturePtr> input_textures;
|
||||||
for (const auto &entry : clips) {
|
for (const auto &entry : clips) {
|
||||||
if (entry.first == kOfxImageEffectOutputClipName) {
|
if (entry.first == kOfxImageEffectOutputClipName) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
OliveClipInstance *input_clip =
|
OliveClipInstance *input_clip =
|
||||||
dynamic_cast<OliveClipInstance *>(instance->getClip(entry.first));
|
dynamic_cast<OliveClipInstance *>(instance->getClip(entry.first));
|
||||||
if (input_clip) {
|
if (!input_clip) {
|
||||||
QString clip_key = QString::fromStdString(entry.first);
|
continue;
|
||||||
TexturePtr input_tex = values.value(clip_key).toTexture();
|
}
|
||||||
if (!input_tex &&
|
QString clip_key = QString::fromStdString(entry.first);
|
||||||
entry.first == kOfxImageEffectSimpleSourceClipName) {
|
TexturePtr input_tex = values.value(clip_key).toTexture();
|
||||||
input_tex = values.value(kTextureInput).toTexture();
|
if (!input_tex &&
|
||||||
}
|
entry.first == kOfxImageEffectSimpleSourceClipName) {
|
||||||
if (input_tex) {
|
input_tex = values.value(kTextureInput).toTexture();
|
||||||
input_clip->setInputTexture(input_tex, frame);
|
}
|
||||||
}
|
if (input_tex) {
|
||||||
|
input_textures[entry.first] = input_tex;
|
||||||
|
input_clip->setInputTexture(input_tex, frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,13 +531,40 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
// the clip component/depth logic and caches away the components and depth.
|
// the clip component/depth logic and caches away the components and depth.
|
||||||
bool ok = instance->getClipPreferences();
|
bool ok = instance->getClipPreferences();
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "OFX getClipPreferences failed for plugin="
|
||||||
|
<< PluginIdForInstance(instance);
|
||||||
|
MarkRenderFailure(destination);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
olive::VideoParams output_params = destination_params;
|
||||||
|
if (ApplyClipPreferencesToParams(*clip, &output_params)) {
|
||||||
|
clip->setParams(output_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &entry : input_textures) {
|
||||||
|
OliveClipInstance *input_clip =
|
||||||
|
dynamic_cast<OliveClipInstance *>(instance->getClip(entry.first));
|
||||||
|
if (!input_clip) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
olive::VideoParams input_params = entry.second->params();
|
||||||
|
if (ApplyClipPreferencesToParams(*input_clip, &input_params)) {
|
||||||
|
input_clip->setParams(input_params);
|
||||||
|
}
|
||||||
|
input_clip->setInputTexture(entry.second, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
clip->setRegionOfDefinition(regionOfDefinition, frame);
|
||||||
|
clip->setOutputTexture(destination, frame);
|
||||||
|
|
||||||
stat = instance->beginRenderAction(0, numFramesToRender,
|
stat = instance->beginRenderAction(0, numFramesToRender,
|
||||||
1.0, false, renderScale, true,
|
1.0, false, renderScale, true,
|
||||||
interactive);
|
interactive);
|
||||||
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||||
|
LogOfxFailure("beginRender", stat, instance);
|
||||||
|
MarkRenderFailure(destination);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,19 +583,33 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
std::map<OFX::Host::ImageEffect::ClipInstance *, OfxRectD> rois;
|
std::map<OFX::Host::ImageEffect::ClipInstance *, OfxRectD> rois;
|
||||||
stat = instance->getRegionOfInterestAction(frame, renderScale,
|
stat = instance->getRegionOfInterestAction(frame, renderScale,
|
||||||
regionOfInterest, rois);
|
regionOfInterest, rois);
|
||||||
assert(stat == kOfxStatOK || stat == kOfxStatReplyDefault);
|
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||||
|
LogOfxFailure("getRegionOfInterest", stat, instance);
|
||||||
|
MarkRenderFailure(destination);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// render a frame
|
// render a frame
|
||||||
const char *render_field = GetRenderFieldForParams(destination_params);
|
const char *render_field = GetRenderFieldForParams(destination_params);
|
||||||
stat = instance->renderAction(0, render_field, renderWindow, renderScale,
|
stat = instance->renderAction(0, render_field, renderWindow, renderScale,
|
||||||
true, interactive, interactive);
|
true, interactive, interactive);
|
||||||
assert(stat == kOfxStatOK);
|
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||||
|
LogOfxFailure("render", stat, instance);
|
||||||
|
MarkRenderFailure(destination);
|
||||||
|
instance->endRenderAction(0, numFramesToRender, 1.0, interactive,
|
||||||
|
renderScale, true, interactive);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// get the output image buffer (CPU path only)
|
// get the output image buffer (CPU path only)
|
||||||
std::shared_ptr<OFX::Host::ImageEffect::Image> output_image;
|
std::shared_ptr<OFX::Host::ImageEffect::Image> output_image;
|
||||||
if (!use_opengl) {
|
if (!use_opengl) {
|
||||||
output_image = clip->getOutputImage(frame);
|
output_image = clip->getOutputImage(frame);
|
||||||
if (!output_image) {
|
if (!output_image) {
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "OFX getOutputImage returned null for plugin="
|
||||||
|
<< PluginIdForInstance(instance);
|
||||||
|
MarkRenderFailure(destination);
|
||||||
instance->endRenderAction(frame, numFramesToRender, 1.0, interactive,
|
instance->endRenderAction(frame, numFramesToRender, 1.0, interactive,
|
||||||
renderScale, true, interactive);
|
renderScale, true, interactive);
|
||||||
return;
|
return;
|
||||||
@@ -424,12 +629,27 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
if (!use_opengl) {
|
if (!use_opengl) {
|
||||||
AVFramePtr frame_ptr = create_avframe_from_ofx_image(*output_image);
|
AVFramePtr frame_ptr = create_avframe_from_ofx_image(*output_image);
|
||||||
if (!frame_ptr) {
|
if (!frame_ptr) {
|
||||||
|
frame_ptr = create_avframe_from_ofx_image_with_params(
|
||||||
|
*output_image, output_params);
|
||||||
|
}
|
||||||
|
if (!frame_ptr) {
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "OFX output image conversion failed for plugin="
|
||||||
|
<< PluginIdForInstance(instance);
|
||||||
instance->endRenderAction(0, numFramesToRender, 1.0, interactive,
|
instance->endRenderAction(0, numFramesToRender, 1.0, interactive,
|
||||||
renderScale, true, interactive);
|
renderScale, true, interactive);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AVFramePtr converted = ConvertFrameIfNeeded(frame_ptr, destination_params);
|
AVFramePtr converted = ConvertFrameIfNeeded(frame_ptr, destination_params);
|
||||||
destination->handleFrame(converted);
|
destination->handleFrame(converted);
|
||||||
|
if (destination->renderer() && converted && converted->data[0]) {
|
||||||
|
int linesize_pixels =
|
||||||
|
LinesizeToPixels(destination_params, converted->linesize[0]);
|
||||||
|
if (linesize_pixels <= 0) {
|
||||||
|
linesize_pixels = destination_params.effective_width();
|
||||||
|
}
|
||||||
|
destination->Upload(converted->data[0], linesize_pixels);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
AVFramePtr frame_ptr =
|
AVFramePtr frame_ptr =
|
||||||
ReadbackTextureToFrame(destination, destination_params);
|
ReadbackTextureToFrame(destination, destination_params);
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ add_executable(olive-gtest
|
|||||||
plugin_support_test.cpp
|
plugin_support_test.cpp
|
||||||
plugin_support_image_test.cpp
|
plugin_support_image_test.cpp
|
||||||
plugin_support_clip_test.cpp
|
plugin_support_clip_test.cpp
|
||||||
|
plugin_render_pipeline_test.cpp
|
||||||
|
plugin_ofx_integration_test.cpp
|
||||||
codec_frame_test.cpp
|
codec_frame_test.cpp
|
||||||
codec_exportcodec_test.cpp
|
codec_exportcodec_test.cpp
|
||||||
codec_exportformat_test.cpp
|
codec_exportformat_test.cpp
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavutil/frame.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "common/ffmpegutils.h"
|
||||||
|
#include "node/value.h"
|
||||||
|
#include "pluginSupport/OliveHost.h"
|
||||||
|
#include "pluginSupport/OlivePluginInstance.h"
|
||||||
|
#include "render/job/pluginjob.h"
|
||||||
|
#include "render/plugin/pluginrenderer.h"
|
||||||
|
#include "render/texture.h"
|
||||||
|
#include "render/videoparams.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
olive::TexturePtr CreateSolidTexture(const olive::VideoParams ¶ms)
|
||||||
|
{
|
||||||
|
olive::AVFramePtr frame = olive::CreateAVFramePtr();
|
||||||
|
frame->format = olive::FFmpegUtils::GetFFmpegPixelFormat(
|
||||||
|
params.format(), params.channel_count());
|
||||||
|
frame->width = params.width();
|
||||||
|
frame->height = params.height();
|
||||||
|
if (frame->format == AV_PIX_FMT_NONE) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (av_frame_get_buffer(frame.get(), 0) < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (av_frame_make_writable(frame.get()) < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int linesize = frame->linesize[0];
|
||||||
|
for (int y = 0; y < frame->height; ++y) {
|
||||||
|
std::memset(frame->data[0] + y * linesize, 0x7f, linesize);
|
||||||
|
}
|
||||||
|
|
||||||
|
olive::TexturePtr texture = std::make_shared<olive::Texture>(params);
|
||||||
|
texture->handleFrame(frame);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(PluginIntegration, ChromaKeyerCreateAndRender)
|
||||||
|
{
|
||||||
|
const char *itest = std::getenv("OAK_OFX_ITEST");
|
||||||
|
if (!itest || std::string(itest) != "1") {
|
||||||
|
GTEST_SKIP() << "OAK_OFX_ITEST not enabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *path = std::getenv("OAK_OFX_PLUGIN_PATH");
|
||||||
|
if (!path || std::string(path).empty()) {
|
||||||
|
GTEST_SKIP() << "OAK_OFX_PLUGIN_PATH not set";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string plugin_id = "net.sf.openfx.ChromaKeyerPlugin";
|
||||||
|
if (const char *env_id = std::getenv("OAK_OFX_PLUGIN_ID")) {
|
||||||
|
if (*env_id) {
|
||||||
|
plugin_id = env_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
olive::plugin::loadPlugins(QString::fromUtf8(path));
|
||||||
|
|
||||||
|
auto *cache = OFX::Host::PluginCache::getPluginCache();
|
||||||
|
OFX::Host::Plugin *found = nullptr;
|
||||||
|
for (auto *plug : cache->getPlugins()) {
|
||||||
|
if (plug && plug->getIdentifier() == plugin_id) {
|
||||||
|
found = plug;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
GTEST_SKIP() << "Plugin not found: " << plugin_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *image_effect =
|
||||||
|
dynamic_cast<OFX::Host::ImageEffect::ImageEffectPlugin *>(found);
|
||||||
|
ASSERT_TRUE(image_effect);
|
||||||
|
|
||||||
|
const auto &contexts = image_effect->getContexts();
|
||||||
|
std::string context = kOfxImageEffectContextFilter;
|
||||||
|
if (!contexts.empty() &&
|
||||||
|
contexts.find(kOfxImageEffectContextFilter) == contexts.end()) {
|
||||||
|
context = *contexts.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
OFX::Host::ImageEffect::Instance *instance =
|
||||||
|
image_effect->createInstance(context, nullptr);
|
||||||
|
ASSERT_TRUE(instance);
|
||||||
|
|
||||||
|
auto *olive_instance =
|
||||||
|
dynamic_cast<olive::plugin::OlivePluginInstance *>(instance);
|
||||||
|
ASSERT_TRUE(olive_instance);
|
||||||
|
|
||||||
|
olive::VideoParams params(320, 240, olive::core::PixelFormat::U8, 4);
|
||||||
|
olive_instance->setVideoParam(params);
|
||||||
|
|
||||||
|
olive::TexturePtr input = CreateSolidTexture(params);
|
||||||
|
ASSERT_TRUE(input);
|
||||||
|
|
||||||
|
olive::NodeValueRow row;
|
||||||
|
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
|
||||||
|
olive::NodeValue(olive::NodeValue::kTexture, input));
|
||||||
|
row.insert(QStringLiteral("Bg"),
|
||||||
|
olive::NodeValue(olive::NodeValue::kTexture, input));
|
||||||
|
|
||||||
|
olive::plugin::PluginJob job(instance, nullptr, row);
|
||||||
|
olive::TexturePtr output = std::make_shared<olive::Texture>(params);
|
||||||
|
|
||||||
|
olive::plugin::PluginRenderer renderer;
|
||||||
|
renderer.RenderPlugin(input, job, output.get(), params, true, false);
|
||||||
|
|
||||||
|
EXPECT_TRUE(output->frame());
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "node/traverser.h"
|
||||||
|
#include "node/value.h"
|
||||||
|
#include "render/job/pluginjob.h"
|
||||||
|
#include "render/texture.h"
|
||||||
|
#include "render/videoparams.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class PluginJobTraverser : public olive::NodeTraverser {
|
||||||
|
public:
|
||||||
|
void Resolve(olive::NodeValue &value)
|
||||||
|
{
|
||||||
|
ResolveJobs(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool called() const
|
||||||
|
{
|
||||||
|
return called_;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
olive::TexturePtr ProcessPluginJob(olive::TexturePtr /*texture*/,
|
||||||
|
olive::TexturePtr destination,
|
||||||
|
const olive::Node * /*node*/) override
|
||||||
|
{
|
||||||
|
called_ = true;
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool called_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(PluginRenderPipeline, PluginJobIsResolved)
|
||||||
|
{
|
||||||
|
olive::VideoParams params(320, 240, olive::core::PixelFormat::U8, 4);
|
||||||
|
|
||||||
|
olive::plugin::PluginJob job(nullptr, nullptr, olive::NodeValueRow());
|
||||||
|
olive::TexturePtr job_tex = olive::Texture::Job(params, job);
|
||||||
|
|
||||||
|
olive::NodeValue val(olive::NodeValue::kTexture, job_tex);
|
||||||
|
|
||||||
|
PluginJobTraverser traverser;
|
||||||
|
traverser.SetCacheVideoParams(params);
|
||||||
|
traverser.Resolve(val);
|
||||||
|
|
||||||
|
EXPECT_TRUE(traverser.called());
|
||||||
|
ASSERT_TRUE(val.toTexture());
|
||||||
|
EXPECT_NE(val.toTexture().get(), job_tex.get());
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "oak-video-editor",
|
||||||
|
"version-string": "0.0.0",
|
||||||
|
"dependencies": [
|
||||||
|
"ffmpeg",
|
||||||
|
"openimageio",
|
||||||
|
"opencolorio",
|
||||||
|
"openexr",
|
||||||
|
"expat",
|
||||||
|
"portaudio"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user