solve problem invalid roi and param

This commit is contained in:
2026-01-17 16:41:03 +08:00
parent 894ee5c0da
commit a2698e7ef4
4 changed files with 226 additions and 82 deletions
+122 -1
View File
@@ -24,6 +24,111 @@
#include <algorithm>
#include <cstring>
#include <olive/core/core.h>
#include <QByteArray>
#include <QHash>
#include <QVariant>
#include <QVector2D>
#include <QVector3D>
namespace {
QHash<QString, QHash<QString, QVariant>> g_plugin_param_defaults;
QVariant DefaultValueForParam(const OFX::Host::Param::Base *param)
{
if (!param) {
return QVariant();
}
const std::string &ofxType = param->getType();
const auto &props = param->getProperties();
if (ofxType == kOfxParamTypeInteger ||
ofxType == kOfxParamTypeChoice) {
return props.getIntProperty(kOfxParamPropDefault);
}
if (ofxType == kOfxParamTypeBoolean) {
return props.getIntProperty(kOfxParamPropDefault) != 0;
}
if (ofxType == kOfxParamTypeDouble) {
return props.getDoubleProperty(kOfxParamPropDefault);
}
if (ofxType == kOfxParamTypeString ||
ofxType == kOfxParamTypeStrChoice ||
ofxType == kOfxParamTypeCustom) {
return QString::fromStdString(
props.getStringProperty(kOfxParamPropDefault));
}
if (ofxType == kOfxParamTypeRGB ||
ofxType == kOfxParamTypeRGBA) {
const int count = (ofxType == kOfxParamTypeRGBA) ? 4 : 3;
double values[4] = {0.0, 0.0, 0.0, 1.0};
props.getDoublePropertyN(kOfxParamPropDefault, values, count);
const double alpha = (count == 4) ? values[3] : 1.0;
return QVariant::fromValue(
olive::core::Color(values[0], values[1], values[2], alpha));
}
if (ofxType == kOfxParamTypeDouble2D ||
ofxType == kOfxParamTypeDouble3D ||
ofxType == kOfxParamTypeInteger2D ||
ofxType == kOfxParamTypeInteger3D) {
const bool is_double =
(ofxType == kOfxParamTypeDouble2D ||
ofxType == kOfxParamTypeDouble3D);
const int count = (ofxType == kOfxParamTypeDouble2D ||
ofxType == kOfxParamTypeInteger2D)
? 2
: 3;
if (is_double) {
double values[3] = {0.0, 0.0, 0.0};
props.getDoublePropertyN(kOfxParamPropDefault, values, count);
if (count == 2) {
return QVector2D(values[0], values[1]);
}
return QVector3D(values[0], values[1], values[2]);
}
int values[3] = {0, 0, 0};
props.getIntPropertyN(kOfxParamPropDefault, values, count);
if (count == 2) {
return QVector2D(values[0], values[1]);
}
return QVector3D(values[0], values[1], values[2]);
}
if (ofxType == kOfxParamTypeBytes) {
return QByteArray();
}
return QVariant();
}
QHash<QString, QVariant>
BuildDefaultValues(const std::map<std::string, OFX::Host::Param::Instance *> &params)
{
QHash<QString, QVariant> defaults;
for (const auto &param : params) {
const std::string &ofxType = param.second->getType();
if (ofxType == kOfxParamTypeGroup ||
ofxType == kOfxParamTypePage ||
ofxType == kOfxParamTypePushButton) {
continue;
}
const auto &props = param.second->getProperties();
if (props.getIntProperty(kOfxParamPropSecret) != 0) {
continue;
}
const QString input_id =
QString::fromStdString(param.second->getName());
if (input_id.isEmpty()) {
continue;
}
QVariant default_value = DefaultValueForParam(param.second);
if (!default_value.isValid()) {
continue;
}
defaults.insert(input_id, default_value);
}
return defaults;
}
}
static QString ClipLabelForName(const std::string &name,
const OFX::Host::ImageEffect::ClipDescriptor *desc)
{
@@ -58,6 +163,14 @@ olive::plugin::PluginNode::PluginNode(
QHash<QString, QString> page_for_param;
auto params=plugin_instance_->getParams();
const QString plugin_id = QString::fromStdString(
plugin_instance_->getPlugin()->getIdentifier());
auto defaults_iter = g_plugin_param_defaults.find(plugin_id);
if (defaults_iter == g_plugin_param_defaults.end()) {
g_plugin_param_defaults.insert(plugin_id, BuildDefaultValues(params));
defaults_iter = g_plugin_param_defaults.find(plugin_id);
}
const QHash<QString, QVariant> &defaults = defaults_iter.value();
for (auto param: params) {
const std::string &ofxType = param.second->getType();
if (ofxType == kOfxParamTypeGroup) {
@@ -135,7 +248,15 @@ olive::plugin::PluginNode::PluginNode(
if (type == NodeValue::kNone) {
continue;
}
AddInput(input_id, type);
QVariant default_value = defaults.value(input_id, QVariant());
if (default_value.isValid()) {
AddInput(input_id, type, default_value);
if (type != NodeValue::kPushButton) {
SetStandardValue(input_id, default_value);
}
} else {
AddInput(input_id, type);
}
const QString label =
QString::fromStdString(param.second->getLabel());
if (!label.isEmpty()) {
+7 -19
View File
@@ -365,24 +365,18 @@ bool olive::plugin::OliveClipInstance::getConnected() const
return true;
}
#endif
for (auto it = images_.cbegin(); it != images_.cend(); ++it) {
if (it.value()) {
return true;
}
}
return false;
if(images_.empty())
return false;
return true;
}
#ifdef OFX_SUPPORTS_OPENGLRENDER
if (!input_textures_.isEmpty()) {
return true;
}
#endif
for (auto it = images_.cbegin(); it != images_.cend(); ++it) {
if (it.value()) {
return true;
}
}
return false;
if(images_.empty())
return false;
return true;
}
double olive::plugin::OliveClipInstance::getUnmappedFrameRate() const
{
@@ -492,13 +486,7 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
return;
}
VideoParams incoming = texture->params();
// AI wrote this. Why?
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
input_textures_.insert(time, texture);
+21 -4
View File
@@ -21,6 +21,8 @@
#ifndef PARAM_INSTANCE_H
#define PARAM_INSTANCE_H
#include "olive/core/util/rational.h"
#include "pluginSupport/OlivePluginInstance.h"
#include <QString>
#include <QVector2D>
#include <QVector3D>
@@ -30,6 +32,8 @@
#include "node/plugins/Plugin.h"
#include "core.h"
#include "undo/undocommand.h"
#include <iostream>
#include <qlogging.h>
namespace olive
{
namespace plugin
@@ -247,6 +251,11 @@ protected:
OFX::Host::Param::Descriptor& _descriptor;
bool has_value_ = false;
bool value_ = false;
bool DefaultValue() const
{
return _descriptor.getProperties()
.getIntProperty(kOfxParamPropDefault) != 0;
}
public:
BooleanInstance(std::shared_ptr<PluginNode> effect, const std::string& name, OFX::Host::Param::Descriptor& descriptor)
: OFX::Host::Param::BooleanInstance(descriptor)
@@ -270,8 +279,8 @@ public:
data = variant.toBool();
return kOfxStatOK;
}
data = false;
return kOfxStatErrValue;
data = DefaultValue();
return kOfxStatOK;
}
OfxStatus get(OfxTime time, bool& data)
{
@@ -282,12 +291,20 @@ public:
QVariant variant =
node->GetValueAtTime(_descriptor.getName().c_str(),
rational::fromDouble(time));
if (variant.isNull()){
qWarning().noquote()<<"Boolean get failed: Varient is null" << time << rational::fromDouble(time).toDouble();
}
if (!variant.isValid()) {
qWarning().noquote()
<< "Boolean get failed: Varient is invalid" << time
<< rational::fromDouble(time).toDouble();
}
if (variant.canConvert<bool>()) {
data = variant.toBool();
return kOfxStatOK;
}
data = false;
return kOfxStatErrValue;
data = DefaultValue();
return kOfxStatOK;
}
OfxStatus set(bool data)
{
+76 -58
View File
@@ -1369,11 +1369,11 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
int numFramesToRender=1;
// Output Clip
OliveClipInstance *output_clip=dynamic_cast<plugin::OliveClipInstance *>(instance->getClip("Output"));
if (!output_clip) {
return;
}
output_clip->setParams(destination_params);
// ensure the instance was created
OfxStatus stat = kOfxStatOK;
@@ -1386,7 +1386,7 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
}
}
// call get region of interest on each of the inputs
OfxTime frame = job.time_seconds();
const auto &clips = olive_instance->getDescriptor().getClips();
@@ -1441,13 +1441,45 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
input_clips[entry.first] = input_clip;
}
}
// call getClipPreferences to know which format plugin requires
OFX::Host::Property::Set args;
args.setDoubleProperty(kOfxPropTime, frame);
double render_scale_array[] = {
renderScale.x, renderScale.y
} ;args.setDoublePropertyN(kOfxImageEffectPropRenderScale, render_scale_array, 2);
};
args.setDoublePropertyN(kOfxImageEffectPropRenderScale, render_scale_array, 2);
instance->setupClipPreferencesArgs(args);
instance->getClipPreferences();
// now we need to call getClipPreferences on the instance so that it does
// the clip component/depth logic and caches away the components and depth.
bool ok = instance->getClipPreferences();
if (!ok) {
qWarning().noquote() << "OFX getClipPreferences failed for plugin="
<< PluginIdForInstance(instance);
MarkRenderFailure(destination);
return;
}
/// RoI is in canonical coords.
OfxRectD regionOfInterest;
regionOfInterest.x1 = 0.0;
regionOfInterest.y1 = 0.0;
regionOfInterest.x2 = destination_params.width() * destination_params.pixel_aspect_ratio().toDouble();
regionOfInterest.y2 = destination_params.height();
OfxRectD regionOfDefinition = regionOfInterest;
output_clip->setRegionOfDefinition(regionOfDefinition, frame);
output_clip->setOutputTexture(destination, frame);
// get the RoI for each input clip
// the regions of interest for each input clip are returned in a std::map
// on a real host, these will be the regions of each input clip that the
// effect needs to render a given frame (clipped to the RoD).
//
// In our example we are doing full frame fetches regardless.
// set correct format for input
for (const auto &entry : input_clips) {
if (entry.first == kOfxImageEffectOutputClipName) {
continue;
@@ -1472,21 +1504,35 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
VideoParams params = input_tex->params();
params.set_format(PixelFormat::from_ofx(bitdepth));
params.set_channel_count(component);
ConvertTextureForParams(input_tex, params) ;
ConvertTextureForParams(input_tex, params);
OfxRectD rod;
rod.x1 = 0;
rod.y1 = 0;
rod.x2 = params.width() * params.pixel_aspect_ratio().toDouble();
rod.y2 = params.height();
input_clip->setRegionOfDefinition(rod, frame);
input_clip->setInputTexture(input_tex,frame);
input_clips[entry.first] = input_clip;
}
}
// now we need to call getClipPreferences on the instance so that it does
// the clip component/depth logic and caches away the components and depth.
bool ok = instance->getClipPreferences();
if (!ok) {
qWarning().noquote()
<< "OFX getClipPreferences failed for plugin="
<< PluginIdForInstance(instance);
std::map<OFX::Host::ImageEffect::ClipInstance *, OfxRectD> rois;
stat = instance->getRegionOfInterestAction(frame, renderScale,
regionOfInterest, rois);
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
LogOfxFailure("getRegionOfInterest", stat, instance);
MarkRenderFailure(destination);
return;
}
// set correct format for output
VideoParams output_params = destination_params; // params for plugin
std::string bitdepth =
output_clip->getProps().getStringProperty(kOfxImageEffectPropPixelDepth);
std::string component =
output_clip->getProps().getStringProperty(kOfxImageEffectPropComponents);
output_params.set_format(PixelFormat::from_ofx(bitdepth));
output_params.set_channel_count(component);
output_clip->setParams(output_params);
// The render window is in pixel coordinates
// ie: render scale and a PAR of not 1
OfxRectI renderWindow;
@@ -1494,18 +1540,7 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
renderWindow.x2 = destination_params.width();
renderWindow.y2 = destination_params.height();
/// RoI is in canonical coords.
OfxRectD regionOfInterest;
regionOfInterest.x1 = 0.0;
regionOfInterest.y1 = 0.0;
regionOfInterest.x2 = destination_params.width();
regionOfInterest.y2 = destination_params.height();
OfxRectD regionOfDefinition = regionOfInterest;
output_clip->setRegionOfDefinition(regionOfDefinition, frame);
output_clip->setOutputTexture(destination, frame);
stat = instance->beginRenderAction(frame, numFramesToRender,
1.0, false, renderScale, true,
interactive);
@@ -1521,22 +1556,9 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
AttachOutputTexture(destination);
}
#endif
// get the RoI for each input clip
// the regions of interest for each input clip are returned in a std::map
// on a real host, these will be the regions of each input clip that the
// effect needs to render a given frame (clipped to the RoD).
//
// In our example we are doing full frame fetches regardless.
std::map<OFX::Host::ImageEffect::ClipInstance *, OfxRectD> rois;
stat = instance->getRegionOfInterestAction(frame, renderScale,
regionOfInterest, rois);
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
LogOfxFailure("getRegionOfInterest", stat, instance);
MarkRenderFailure(destination);
return;
}
if (!destination_params.is_valid()) {
if (!output_params.is_valid()) {
qWarning().noquote()
<< "OFX render skipped due to invalid output params for plugin="
<< PluginIdForInstance(instance);
@@ -1547,12 +1569,12 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
}
// render a frame
const char *render_field = GetRenderFieldForParams(destination_params);
const char *render_field = GetRenderFieldForParams(output_params);
stat = instance->renderAction(frame, render_field, renderWindow, renderScale,
true, interactive, interactive);
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
LogOfxFailure("render", stat, instance);
LogClipState("output", output_clip, &destination_params);
LogClipState("output", output_clip, &output_params);
for (const auto &entry : input_clips) {
const auto params_it = input_params.find(entry.first);
const olive::VideoParams *params =
@@ -1601,11 +1623,9 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
}
if (!use_opengl) {
AVFramePtr frame_ptr = create_avframe_from_ofx_image(*output_image);
if (!frame_ptr) {
frame_ptr = create_avframe_from_ofx_image_with_params(
*output_image, destination_params);
}
AVFramePtr 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="
@@ -1614,20 +1634,20 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
renderScale, true, interactive);
return;
}
//AVFramePtr converted = ConvertFrameIfNeeded(frame_ptr, destination_params);
AVFramePtr converted = ConvertFrameIfNeeded(frame_ptr, destination_params);
const AVPixelFormat expected_fmt =
GetDestinationAVPixelFormat(destination_params);
destination->handleFrame(frame_ptr);
if (destination->renderer() && frame_ptr && frame_ptr->data[0] &&
destination->handleFrame(converted);
if (destination->renderer() && converted && converted->data[0] &&
(expected_fmt == AV_PIX_FMT_NONE ||
frame_ptr->format == expected_fmt)) {
converted->format == expected_fmt)) {
int linesize_pixels =
LinesizeToPixels(destination_params, frame_ptr->linesize[0]);
LinesizeToPixels(destination_params, converted->linesize[0]);
if (linesize_pixels <= 0) {
linesize_pixels = destination_params.effective_width();
}
destination->Upload(frame_ptr->data[0], linesize_pixels);
} else if (destination->renderer() && frame_ptr && frame_ptr->data[0]) {
//destination->Upload(converted->data[0], linesize_pixels);
} else if (destination->renderer() && converted && converted->data[0]) {
qWarning().noquote()
<< "OFX output pixel format mismatch for plugin="
<< PluginIdForInstance(instance);
@@ -1639,8 +1659,6 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
DetachOutputTexture();
instance->contextDetachedAction();
#endif
}
/*
if (frame_ptr && destination) {
AVFramePtr converted =
ConvertFrameIfNeeded(frame_ptr, destination_params);
@@ -1650,8 +1668,8 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
if (destination->renderer() && converted && converted->data[0] &&
(expected_fmt == AV_PIX_FMT_NONE ||
converted->format == expected_fmt)) {
int linesize_pixels =
LinesizeToPixels(destination_params, converted->linesize[0]);
int linesize_pixels = LinesizeToPixels(destination_params,
converted->linesize[0]);
if (linesize_pixels <= 0) {
linesize_pixels = destination_params.effective_width();
}
@@ -1664,7 +1682,7 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
}
}
}
*/
instance->endRenderAction(frame, numFramesToRender, 1.0, interactive, renderScale, true,interactive
);