Try to fix plugin issue
This commit is contained in:
@@ -23,12 +23,14 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <qtypes.h>
|
||||
#include <QDebug>
|
||||
#define GL_PREAMBLE //QMutexLocker __l(&global_opengl_mutex);
|
||||
#include "pluginrenderer.h"
|
||||
#include "pluginSupport/OliveClip.h"
|
||||
#include "pluginSupport/OlivePluginInstance.h"
|
||||
#include "common/ffmpegutils.h"
|
||||
#include "ofxImageEffect.h"
|
||||
#include "ofxhUtilities.h"
|
||||
extern "C"{
|
||||
#include <libavutil/pixfmt.h>
|
||||
#include <libavutil/pixdesc.h>
|
||||
@@ -67,6 +69,10 @@ static AVPixelFormat GetOfxAVPixelFormat(const OFX::Host::ImageEffect::Image &im
|
||||
pix_fmt = AV_PIX_FMT_GRAY8;
|
||||
} else if (pixel_format == olive::core::PixelFormat::U16) {
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
if (!data_ptr) {
|
||||
@@ -103,9 +211,14 @@ static olive::AVFramePtr create_avframe_from_ofx_image(OFX::Host::ImageEffect::I
|
||||
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) {
|
||||
AVPixelFormat pix_fmt = GetDestinationAVPixelFormat(params);
|
||||
if (pix_fmt == AV_PIX_FMT_NONE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int bytes_per_pixel =
|
||||
params.channel_count() * params.format().byte_count();
|
||||
if (bytes_per_pixel <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -146,6 +259,10 @@ static AVPixelFormat GetDestinationAVPixelFormat(const olive::VideoParams ¶m
|
||||
pix_fmt = AV_PIX_FMT_GRAY8;
|
||||
} else if (params.format() == olive::core::PixelFormat::U16) {
|
||||
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;
|
||||
@@ -280,6 +397,48 @@ static olive::AVFramePtr ConvertFrameIfNeeded(olive::AVFramePtr src,
|
||||
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,
|
||||
olive::Texture *destination,
|
||||
olive::VideoParams destination_params,
|
||||
@@ -295,6 +454,7 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
||||
destination && destination->renderer() && destination->id().isValid();
|
||||
if (olive_instance) {
|
||||
olive_instance->setOpenGLEnabled(use_opengl);
|
||||
olive_instance->setVideoParam(destination_params);
|
||||
}
|
||||
|
||||
// current render scale of 1
|
||||
@@ -330,36 +490,40 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
||||
}
|
||||
clip->setParams(destination_params);
|
||||
|
||||
OfxStatus stat;
|
||||
stat = instance->createInstanceAction();
|
||||
if(stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||
return;
|
||||
OfxStatus stat = kOfxStatOK;
|
||||
if (olive_instance && !olive_instance->isCreated()) {
|
||||
stat = instance->createInstanceAction();
|
||||
if(stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||
LogOfxFailure("createInstance", stat, instance);
|
||||
MarkRenderFailure(destination);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// call get region of interest on each of the inputs
|
||||
OfxTime frame = 0;
|
||||
|
||||
clip->setRegionOfDefinition(regionOfDefinition, frame);
|
||||
clip->setOutputTexture(destination, frame);
|
||||
|
||||
const NodeValueRow &values = job.GetValues();
|
||||
const auto &clips = instance->getDescriptor().getClips();
|
||||
std::map<std::string, TexturePtr> input_textures;
|
||||
for (const auto &entry : clips) {
|
||||
if (entry.first == kOfxImageEffectOutputClipName) {
|
||||
continue;
|
||||
}
|
||||
OliveClipInstance *input_clip =
|
||||
dynamic_cast<OliveClipInstance *>(instance->getClip(entry.first));
|
||||
if (input_clip) {
|
||||
QString clip_key = QString::fromStdString(entry.first);
|
||||
TexturePtr input_tex = values.value(clip_key).toTexture();
|
||||
if (!input_tex &&
|
||||
entry.first == kOfxImageEffectSimpleSourceClipName) {
|
||||
input_tex = values.value(kTextureInput).toTexture();
|
||||
}
|
||||
if (input_tex) {
|
||||
input_clip->setInputTexture(input_tex, frame);
|
||||
}
|
||||
if (!input_clip) {
|
||||
continue;
|
||||
}
|
||||
QString clip_key = QString::fromStdString(entry.first);
|
||||
TexturePtr input_tex = values.value(clip_key).toTexture();
|
||||
if (!input_tex &&
|
||||
entry.first == kOfxImageEffectSimpleSourceClipName) {
|
||||
input_tex = values.value(kTextureInput).toTexture();
|
||||
}
|
||||
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.
|
||||
bool ok = instance->getClipPreferences();
|
||||
if (!ok) {
|
||||
qWarning().noquote()
|
||||
<< "OFX getClipPreferences failed for plugin="
|
||||
<< PluginIdForInstance(instance);
|
||||
MarkRenderFailure(destination);
|
||||
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,
|
||||
1.0, false, renderScale, true,
|
||||
interactive);
|
||||
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||
LogOfxFailure("beginRender", stat, instance);
|
||||
MarkRenderFailure(destination);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -392,19 +583,33 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
||||
std::map<OFX::Host::ImageEffect::ClipInstance *, OfxRectD> rois;
|
||||
stat = instance->getRegionOfInterestAction(frame, renderScale,
|
||||
regionOfInterest, rois);
|
||||
assert(stat == kOfxStatOK || stat == kOfxStatReplyDefault);
|
||||
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||
LogOfxFailure("getRegionOfInterest", stat, instance);
|
||||
MarkRenderFailure(destination);
|
||||
return;
|
||||
}
|
||||
|
||||
// render a frame
|
||||
const char *render_field = GetRenderFieldForParams(destination_params);
|
||||
stat = instance->renderAction(0, render_field, renderWindow, renderScale,
|
||||
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)
|
||||
std::shared_ptr<OFX::Host::ImageEffect::Image> output_image;
|
||||
if (!use_opengl) {
|
||||
output_image = clip->getOutputImage(frame);
|
||||
if (!output_image) {
|
||||
qWarning().noquote()
|
||||
<< "OFX getOutputImage returned null for plugin="
|
||||
<< PluginIdForInstance(instance);
|
||||
MarkRenderFailure(destination);
|
||||
instance->endRenderAction(frame, numFramesToRender, 1.0, interactive,
|
||||
renderScale, true, interactive);
|
||||
return;
|
||||
@@ -424,12 +629,27 @@ 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, output_params);
|
||||
}
|
||||
if (!frame_ptr) {
|
||||
qWarning().noquote()
|
||||
<< "OFX output image conversion failed for plugin="
|
||||
<< PluginIdForInstance(instance);
|
||||
instance->endRenderAction(0, numFramesToRender, 1.0, interactive,
|
||||
renderScale, true, interactive);
|
||||
return;
|
||||
}
|
||||
AVFramePtr converted = ConvertFrameIfNeeded(frame_ptr, destination_params);
|
||||
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 {
|
||||
AVFramePtr frame_ptr =
|
||||
ReadbackTextureToFrame(destination, destination_params);
|
||||
|
||||
Reference in New Issue
Block a user