solve some bugs

This commit is contained in:
2026-01-05 18:01:13 +08:00
parent 6b64abb1fa
commit 8ed5660faf
17 changed files with 203 additions and 79 deletions
+5
View File
@@ -140,6 +140,11 @@ Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range,
return kInvalid;
}
if (params.sample_rate() <= 0 || params.channel_count() <= 0) {
qWarning() << "Invalid audio parameters, skipping audio retrieve";
return kInvalid;
}
// Get conform state from ConformManager
ConformManager::Conform conform =
ConformManager::instance()->GetConformState(
+5 -3
View File
@@ -287,9 +287,7 @@ int main(int argc, char *argv[])
}
}
if (!no_plugin->IsSet()) {
olive::plugin::loadPlugins("plugins");
}
const bool load_plugins = !no_plugin->IsSet();
if (crash_option->IsSet()) {
startup_params.set_crash_on_startup(true);
@@ -341,6 +339,10 @@ int main(int argc, char *argv[])
gui_app->setWindowIcon(QIcon(QStringLiteral(":/graphics/oak-logo.png")));
}
if (load_plugins) {
olive::plugin::loadPlugins("plugins");
}
#ifdef _WIN32
// On Windows, users seem to frequently run into a crash caused by their graphics driver not
// supporting framebuffers, which we require. I personally have only been able to recreate this
+6 -3
View File
@@ -88,7 +88,6 @@ void NodeFactory::Initialize()
library_.append(created_node);
}
olive::plugin::loadPlugins(QString());
RegisterPluginNodes();
}
@@ -237,9 +236,13 @@ void NodeFactory::RegisterPluginNodes()
}
const auto &contexts = image_effect->getContexts();
if (contexts.empty()) {
qWarning() << "Skipping OFX plugin with no contexts:"
<< plugin_id;
continue;
}
std::string context = kOfxImageEffectContextFilter;
if (!contexts.empty() &&
contexts.find(kOfxImageEffectContextFilter) == contexts.end()) {
if (contexts.find(kOfxImageEffectContextFilter) == contexts.end()) {
context = *contexts.begin();
}
+24 -15
View File
@@ -20,6 +20,7 @@
#include "render/rendermanager.h"
#include "render/job/pluginjob.h"
#include "pluginSupport/OlivePluginInstance.h"
static QString ClipLabelForName(const std::string &name,
const OFX::Host::ImageEffect::ClipDescriptor *desc)
{
@@ -222,22 +223,30 @@ QString olive::plugin::PluginNode::id() const
return plugin->getIdentifier().data();
}
olive::Node *olive::plugin::PluginNode::copy() const
{
auto *node = new PluginNode(new OlivePluginInstance(*plugin_instance_));
if (!plugin_instance_) {
return node;
}
olive::Node *olive::plugin::PluginNode::copy() const
{
if (!plugin_instance_) {
return nullptr;
}
const auto &contexts = plugin_instance_->getPlugin()->getContexts();
std::string context = kOfxImageEffectContextFilter;
if (!contexts.empty()) {
if (contexts.find(kOfxImageEffectContextFilter) == contexts.end()) {
const auto &contexts = plugin_instance_->getPlugin()->getContexts();
std::string context = kOfxImageEffectContextFilter;
if (!contexts.empty() &&
contexts.find(kOfxImageEffectContextFilter) == contexts.end()) {
context = *contexts.begin();
}
}
node->setPluginInstance(
plugin_instance_->getPlugin()->createInstance(context, node));
return node;
}
auto *instance =
plugin_instance_->getPlugin()->createInstance(context, nullptr);
if (!instance) {
return nullptr;
}
auto *node = new PluginNode(instance);
if (auto *olive_instance =
dynamic_cast<OlivePluginInstance *>(instance)) {
olive_instance->setNode(
std::shared_ptr<PluginNode>(node, [](PluginNode *) {}));
}
return node;
}
+9 -1
View File
@@ -124,7 +124,15 @@ const std::string &olive::plugin::OliveClipInstance::getFieldOrder() const
}
bool olive::plugin::OliveClipInstance::getConnected() const
{
return params_.format() == PixelFormat::INVALID;
if (name_ == kOfxImageEffectOutputClipName) {
return true;
}
#ifdef OFX_SUPPORTS_OPENGLRENDER
if (!input_textures_.isEmpty()) {
return true;
}
#endif
return !images_.isEmpty();
}
double olive::plugin::OliveClipInstance::getUnmappedFrameRate() const
{
+12 -7
View File
@@ -71,15 +71,20 @@ void AddPluginPathsFromEnv(OFX::Host::PluginCache *cache, const char *env_var)
void olive::plugin::loadPlugins(QString path)
{
std::shared_ptr<OliveHost> host = std::make_shared<OliveHost>();
Current::getInstance().setPluginHost(host);
std::shared_ptr<OliveHost> host = Current::getInstance().pluginHost();
std::shared_ptr<ImageEffect::PluginCache> imageEffectPluginCache =
std::make_shared<ImageEffect::PluginCache>(*host);
Current::getInstance().setPluginCache(imageEffectPluginCache);
Current::getInstance().pluginCache();
imageEffectPluginCache->registerInCache(
*OFX::Host::PluginCache::getPluginCache());
if (!host || !imageEffectPluginCache) {
host = std::make_shared<OliveHost>();
Current::getInstance().setPluginHost(host);
imageEffectPluginCache = std::make_shared<ImageEffect::PluginCache>(*host);
Current::getInstance().setPluginCache(imageEffectPluginCache);
imageEffectPluginCache->registerInCache(
*OFX::Host::PluginCache::getPluginCache());
}
OFX::Host::PluginCache *cache = OFX::Host::PluginCache::getPluginCache();
cache->setPluginHostPath("Olive");
+8
View File
@@ -53,6 +53,14 @@ public:
bool pluginSupported(OFX::Host::ImageEffect::ImageEffectPlugin *plugin,
std::string &reason) const override
{
if (!plugin) {
reason = "null plugin";
return false;
}
if (plugin->getContexts().empty()) {
reason = "no supported contexts (describe failed)";
return false;
}
return true;
};
+2 -1
View File
@@ -53,7 +53,8 @@ public:
{
}
OlivePluginInstance(OlivePluginInstance& instance)
: Instance(_plugin, *_descriptor, _context, _interactive)
: Instance(instance._plugin, *instance._descriptor, instance._context,
instance._interactive)
{
_clips=instance._clips;
_created=instance._created;
+5
View File
@@ -68,6 +68,11 @@ public:
virtual Color GetPixelFromTexture(olive::Texture *texture,
const QPointF &pt) override;
QOpenGLContext *context() const
{
return context_;
}
protected:
virtual void Blit(QVariant shader, olive::AcceleratedJob& job,
olive::Texture *destination,
+28 -33
View File
@@ -296,17 +296,6 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
if (olive_instance) {
olive_instance->setOpenGLEnabled(use_opengl);
}
OfxStatus stat;
stat = instance->createInstanceAction();
if(stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
return;
}
// now we need to to call getClipPreferences on the instance so that it does the clip component/depth
// logic and caches away the components and depth on each clip.
bool ok = instance->getClipPreferences();
if (!ok) {
return;
}
// current render scale of 1
OfxPointD renderScale;
@@ -334,37 +323,22 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
int numFramesToRender=1;
stat = instance->beginRenderAction(0, numFramesToRender,
1.0, false, renderScale, true,
interactive);
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
return;
}
#ifdef OFX_SUPPORTS_OPENGLRENDER
if (use_opengl) {
instance->contextAttachedAction();
AttachOutputTexture(destination);
}
#endif
OliveClipInstance *clip=dynamic_cast<plugin::OliveClipInstance *>(instance->getClip("Output"));
if (!clip) {
#ifdef OFX_SUPPORTS_OPENGLRENDER
if (use_opengl) {
DetachOutputTexture();
instance->contextDetachedAction();
}
#endif
instance->endRenderAction(0, numFramesToRender, 1.0, interactive, renderScale, true,interactive
);
return;
}
clip->setParams(destination_params);
OfxStatus stat;
stat = instance->createInstanceAction();
if(stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
return;
}
// call get region of interest on each of the inputs
OfxTime frame = 0;
clip->setParams(destination_params);
clip->setRegionOfDefinition(regionOfDefinition, frame);
clip->setOutputTexture(destination, frame);
@@ -388,6 +362,27 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
}
}
}
// 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) {
return;
}
stat = instance->beginRenderAction(0, numFramesToRender,
1.0, false, renderScale, true,
interactive);
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
return;
}
#ifdef OFX_SUPPORTS_OPENGLRENDER
if (use_opengl) {
instance->contextAttachedAction();
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
+1 -2
View File
@@ -44,8 +44,7 @@ public:
virtual ~PluginRenderer() override{};
void AttachOutputTexture(olive::Texture *texture);
void DetachOutputTexture();
protected:
virtual void RenderPlugin(TexturePtr src, olive::plugin::PluginJob& job,
void RenderPlugin(TexturePtr src, olive::plugin::PluginJob& job,
olive::Texture *destination,
olive::VideoParams destination_params,
bool clear_destination, bool interactive);
+23 -9
View File
@@ -393,8 +393,9 @@ void PreviewAutoCacher::StartCachingAudioRange(ViewerOutput *context,
cache->ClearRequestRange(range);
pending_audio_jobs_.push_back({ node, context, cache, range });
audio_cache_data_[cache].job_tracker.insert(range,
copier_->GetGraphChangeTime());
AudioCacheData &data = audio_cache_data_[cache];
data.context = context;
data.job_tracker.insert(range, copier_->GetGraphChangeTime());
TryRender();
}
@@ -675,6 +676,15 @@ RenderTicketPtr PreviewAutoCacher::RenderAudio(Node *node,
running_audio_tasks_.append(watcher);
AudioParams p = context->GetAudioParams();
const bool invalid_params =
(p.sample_rate() <= 0 || p.channel_count() <= 0);
if (invalid_params) {
AudioParams fallback(
OLIVE_CONFIG("DefaultSequenceAudioFrequency").toInt(),
OLIVE_CONFIG("DefaultSequenceAudioLayout").toULongLong(),
ViewerOutput::kDefaultSampleFormat);
p = fallback;
}
p.set_format(ViewerOutput::kDefaultSampleFormat);
RenderManager::RenderAudioParams rap(node, r, p, RenderMode::kOffline);
@@ -692,13 +702,17 @@ void PreviewAutoCacher::ConformFinished()
// Got an audio conform, requeue all the audio currently needing a conform
last_conform_task_.Acquire();
qDebug() << "CONFORM RESPONSE TEMPORARILY DISABLED";
/*for (auto it=audio_cache_data_.begin(); it!=audio_cache_data_.end(); it++) {
foreach (const TimeRange &range, it.value().needs_conform) {
it.key()->Request(range);
}
it.value().needs_conform.clear();
}*/
for (auto it = audio_cache_data_.begin(); it != audio_cache_data_.end();
it++) {
if (!it.key() || !it.value().context) {
continue;
}
for (const TimeRange &range : it.value().needs_conform) {
it.key()->Request(it.value().context, range);
}
it.value().needs_conform.clear();
}
}
void PreviewAutoCacher::CacheProxyTaskCancelled()
+1
View File
@@ -186,6 +186,7 @@ private:
struct AudioCacheData {
RenderJobTracker job_tracker;
TimeRangeList needs_conform;
ViewerOutput *context = nullptr;
};
std::list<VideoJob> pending_video_jobs_;
+40
View File
@@ -28,6 +28,8 @@
#include "node/block/transition/transition.h"
#include "node/project.h"
#include "rendermanager.h"
#include "render/opengl/openglrenderer.h"
#include "render/plugin/pluginrenderer.h"
#include "pluginSupport/OliveClip.h"
#include "pluginSupport/OliveHost.h"
@@ -606,6 +608,44 @@ void RenderProcessor::ProcessFrameGeneration(TexturePtr destination,
destination->Upload(frame->data(), frame->linesize_pixels());
}
TexturePtr RenderProcessor::ProcessPluginJob(TexturePtr texture,
TexturePtr destination,
const Node *node)
{
(void)node;
if (!render_ctx_ || !texture || !destination) {
return destination;
}
auto *plugin_job =
dynamic_cast<plugin::PluginJob *>(texture->job());
if (!plugin_job) {
return destination;
}
if (!plugin_renderer_) {
auto *gl = dynamic_cast<OpenGLRenderer *>(render_ctx_);
if (!gl || !gl->context()) {
return destination;
}
plugin_renderer_ = std::make_unique<plugin::PluginRenderer>();
plugin_renderer_->Init(gl->context());
plugin_renderer_->PostInit();
}
plugin_renderer_->RenderPlugin(
texture,
*plugin_job,
destination.get(),
destination->params(),
true,
false);
return destination;
}
TexturePtr RenderProcessor::ProcessVideoCacheJob(const CacheJob *val)
{
FramePtr frame = FrameHashCache::LoadCacheFrame(val->GetFilename());
+11
View File
@@ -20,6 +20,7 @@
#define RENDERPROCESSOR_H
#include "node/block/clip/clip.h"
#include <memory>
#include "node/traverser.h"
#include "render/renderer.h"
#include "rendercache.h"
@@ -28,6 +29,10 @@
namespace olive
{
namespace plugin {
class PluginRenderer;
}
class RenderProcessor : public NodeTraverser {
public:
virtual NodeValueDatabase GenerateDatabase(const Node *node,
@@ -66,6 +71,10 @@ protected:
const Node *node,
const GenerateJob *job) override;
virtual TexturePtr ProcessPluginJob(TexturePtr texture,
TexturePtr destination,
const Node *node) override;
virtual TexturePtr ProcessVideoCacheJob(const CacheJob *val) override;
virtual TexturePtr CreateTexture(const VideoParams &p) override;
@@ -100,6 +109,8 @@ private:
Renderer *render_ctx_;
std::unique_ptr<olive::plugin::PluginRenderer> plugin_renderer_;
DecoderCache *decoder_cache_;
ShaderCache *shader_cache_;
+6 -2
View File
@@ -571,10 +571,14 @@ void ViewerWidget::UpdateAudioProcessor()
CloseAudioProcessor();
AudioParams ap = GetConnectedNode()->GetAudioParams();
if (ap.sample_rate() <= 0 || ap.channel_count() <= 0) {
ap = AudioParams(
OLIVE_CONFIG("DefaultSequenceAudioFrequency").toInt(),
OLIVE_CONFIG("DefaultSequenceAudioLayout").toULongLong(),
ViewerOutput::kDefaultSampleFormat);
}
ap.set_format(ViewerOutput::kDefaultSampleFormat);
uint64_t layout =
OLIVE_CONFIG("AudioOutputChannelLayout").toULongLong();
AudioParams packed(
OLIVE_CONFIG("AudioOutputSampleRate").toInt(),
OLIVE_CONFIG("AudioOutputChannelLayout").toULongLong(),
+17 -3
View File
@@ -211,6 +211,9 @@ namespace OFX {
OFX::Host::Property::Set inarg(inargspec);
PluginHandle *ph = getPluginHandle();
if (!ph) {
return nullptr;
}
std::unique_ptr<ImageEffect::Descriptor> newContext( gImageEffectHost->makeDescriptor(getDescriptor(), this));
OfxStatus stat;
@@ -238,7 +241,10 @@ namespace OFX {
/// (not because we are expecting the results to change, but because plugin
/// might get confused otherwise), then a describe_in_context
getPluginHandle();
PluginHandle *ph = getPluginHandle();
if (!ph) {
return nullptr;
}
Descriptor *desc = getContext(context);
@@ -322,7 +328,16 @@ namespace OFX {
/// whether we support this plugin.
bool PluginCache::pluginSupported(OFX::Host::Plugin *p, std::string &reason) const {
return gImageEffectHost->pluginSupported(dynamic_cast<OFX::Host::ImageEffect::ImageEffectPlugin *>(p), reason);
if (!gImageEffectHost) {
reason = "host not initialized";
return false;
}
auto *plugin = dynamic_cast<OFX::Host::ImageEffect::ImageEffectPlugin *>(p);
if (!plugin) {
reason = "not an image effect plugin";
return false;
}
return gImageEffectHost->pluginSupported(plugin, reason);
}
/// get the plugin by label. vermaj and vermin can be specified. if they are not it will
@@ -589,4 +604,3 @@ namespace OFX {
} // Host
} // OFX