尝试解决插件bug
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
CompileFlags:
|
CompileFlags:
|
||||||
Add: []
|
Add: []
|
||||||
Remove: [-mlongcalls, -fstrict-volatile-bitfields, -fno-shrink-wrap, -fno-tree-switch-conversion, -mno-direct-extern-access]
|
Remove: [-mlongcalls, -fstrict-volatile-bitfields, -fno-shrink-wrap, -fno-tree-switch-conversion, -mno-direct-extern-access]
|
||||||
|
CompileFlags:
|
||||||
|
CompilationDatabase: build
|
||||||
Diagnostics:
|
Diagnostics:
|
||||||
Suppress: ['drv_unknown_argument', 'unused-includes', 'pp_file_not_found']
|
Suppress: ['drv_unknown_argument', 'unused-includes', 'pp_file_not_found']
|
||||||
@@ -22,6 +22,10 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -g")
|
|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -g")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -g")
|
||||||
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory)
|
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -DOFX_SUPPORTS_OPENGLRENDER)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOFX_SUPPORTS_OPENGLRENDER")
|
||||||
option(BUILD_QT6 "Build with Qt 6 over 5 (experimental)" ON)
|
option(BUILD_QT6 "Build with Qt 6 over 5 (experimental)" ON)
|
||||||
option(BUILD_DOXYGEN "Build Doxygen documentation" OFF)
|
option(BUILD_DOXYGEN "Build Doxygen documentation" OFF)
|
||||||
option(BUILD_TESTS "Build unit tests" OFF)
|
option(BUILD_TESTS "Build unit tests" OFF)
|
||||||
@@ -55,6 +59,7 @@ if(MSVC)
|
|||||||
/external:W0
|
/external:W0
|
||||||
"$<$<CONFIG:RELEASE>:/O2>"
|
"$<$<CONFIG:RELEASE>:/O2>"
|
||||||
"$<$<COMPILE_LANGUAGE:CXX>:/MP>"
|
"$<$<COMPILE_LANGUAGE:CXX>:/MP>"
|
||||||
|
/DOFX_SUPPORTS_OPENGLRENDER
|
||||||
)
|
)
|
||||||
if (USE_WERROR)
|
if (USE_WERROR)
|
||||||
list(APPEND OLIVE_COMPILE_OPTIONS "/WX")
|
list(APPEND OLIVE_COMPILE_OPTIONS "/WX")
|
||||||
@@ -68,6 +73,8 @@ else()
|
|||||||
-Wextra
|
-Wextra
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
-Wshadow
|
-Wshadow
|
||||||
|
-DOFX_SUPPORTS_OPENGLRENDER
|
||||||
|
|
||||||
)
|
)
|
||||||
if (USE_WERROR)
|
if (USE_WERROR)
|
||||||
list(APPEND OLIVE_COMPILE_OPTIONS "-Werror")
|
list(APPEND OLIVE_COMPILE_OPTIONS "-Werror")
|
||||||
|
|||||||
@@ -122,7 +122,24 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QString input_id = QString::fromStdString(param.second->getName());
|
const QString input_id = QString::fromStdString(param.second->getName());
|
||||||
|
if (input_id.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto &props = param.second->getProperties();
|
||||||
|
if (props.getIntProperty(kOfxParamPropSecret) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (type == NodeValue::kNone) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
AddInput(input_id, type);
|
AddInput(input_id, type);
|
||||||
|
const QString label =
|
||||||
|
QString::fromStdString(param.second->getLabel());
|
||||||
|
if (!label.isEmpty()) {
|
||||||
|
SetInputName(input_id, label);
|
||||||
|
} else {
|
||||||
|
SetInputName(input_id, input_id);
|
||||||
|
}
|
||||||
const QString parent =
|
const QString parent =
|
||||||
QString::fromStdString(param.second->getParentName());
|
QString::fromStdString(param.second->getParentName());
|
||||||
if (!parent.isEmpty()) {
|
if (!parent.isEmpty()) {
|
||||||
@@ -209,7 +226,7 @@ void olive::plugin::PluginNode::Value(const NodeValueRow &value,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tex && plugin_instance_) {
|
if (tex && plugin_instance_) {
|
||||||
PluginJob job(plugin_instance_, this, value);
|
PluginJob job(plugin_instance_, this, value, globals.time().in());
|
||||||
table->Push(NodeValue::kTexture, tex->toJob(job), this);
|
table->Push(NodeValue::kTexture, tex->toJob(job), this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,11 @@
|
|||||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
||||||
#include <QOpenGLFunctions>
|
#include <QOpenGLFunctions>
|
||||||
#endif
|
#endif
|
||||||
|
#include "common/ffmpegutils.h"
|
||||||
|
#include "render/renderer.h"
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libswscale/swscale.h>
|
#include <libswscale/swscale.h>
|
||||||
|
#include <libavutil/pixdesc.h>
|
||||||
}
|
}
|
||||||
namespace {
|
namespace {
|
||||||
const std::string kBitDepthNoneStr(kOfxBitDepthNone);
|
const std::string kBitDepthNoneStr(kOfxBitDepthNone);
|
||||||
@@ -54,6 +56,239 @@ const std::string kImageUnPremultStr(kOfxImageUnPreMultiplied);
|
|||||||
const std::string kImageFieldNoneStr(kOfxImageFieldNone);
|
const std::string kImageFieldNoneStr(kOfxImageFieldNone);
|
||||||
const std::string kImageFieldUpperStr(kOfxImageFieldUpper);
|
const std::string kImageFieldUpperStr(kOfxImageFieldUpper);
|
||||||
const std::string kImageFieldLowerStr(kOfxImageFieldLower);
|
const std::string kImageFieldLowerStr(kOfxImageFieldLower);
|
||||||
|
|
||||||
|
static int BytesToPixels(int byte_linesize, const olive::VideoParams ¶ms)
|
||||||
|
{
|
||||||
|
const int bytes_per_pixel =
|
||||||
|
params.channel_count() * params.format().byte_count();
|
||||||
|
if (bytes_per_pixel <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return byte_linesize / bytes_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int PackedFloatChannels(AVPixelFormat fmt)
|
||||||
|
{
|
||||||
|
switch (fmt) {
|
||||||
|
case AV_PIX_FMT_GRAYF32LE:
|
||||||
|
case AV_PIX_FMT_GRAYF32BE:
|
||||||
|
return 1;
|
||||||
|
case AV_PIX_FMT_RGBF32LE:
|
||||||
|
case AV_PIX_FMT_RGBF32BE:
|
||||||
|
return 3;
|
||||||
|
case AV_PIX_FMT_RGBAF32LE:
|
||||||
|
case AV_PIX_FMT_RGBAF32BE:
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool PackedDstInfo(AVPixelFormat fmt, int *channels,
|
||||||
|
int *bytes_per_component)
|
||||||
|
{
|
||||||
|
switch (fmt) {
|
||||||
|
case AV_PIX_FMT_GRAY8:
|
||||||
|
*channels = 1;
|
||||||
|
*bytes_per_component = 1;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_RGB24:
|
||||||
|
*channels = 3;
|
||||||
|
*bytes_per_component = 1;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_RGBA:
|
||||||
|
*channels = 4;
|
||||||
|
*bytes_per_component = 1;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_GRAY16LE:
|
||||||
|
*channels = 1;
|
||||||
|
*bytes_per_component = 2;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_RGB48LE:
|
||||||
|
*channels = 3;
|
||||||
|
*bytes_per_component = 2;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_RGBA64LE:
|
||||||
|
*channels = 4;
|
||||||
|
*bytes_per_component = 2;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static olive::AVFramePtr ReadbackTextureToFrame(olive::TexturePtr texture,
|
||||||
|
const olive::VideoParams ¶ms)
|
||||||
|
{
|
||||||
|
if (!texture || texture->IsDummy() || !texture->renderer()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVPixelFormat pix_fmt =
|
||||||
|
olive::FFmpegUtils::GetFFmpegPixelFormat(params.format(),
|
||||||
|
params.channel_count());
|
||||||
|
if (pix_fmt == AV_PIX_FMT_NONE) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
|
||||||
|
if (!desc) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) {
|
||||||
|
olive::AVFramePtr frame = olive::CreateAVFramePtr();
|
||||||
|
frame->format = pix_fmt;
|
||||||
|
frame->width = params.width();
|
||||||
|
frame->height = params.height();
|
||||||
|
if (av_frame_get_buffer(frame.get(), 0) < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const int linesize_pixels = BytesToPixels(frame->linesize[0], params);
|
||||||
|
texture->renderer()->DownloadFromTexture(texture->id(), params,
|
||||||
|
frame->data[0],
|
||||||
|
linesize_pixels);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
olive::VideoParams rgba_params(
|
||||||
|
params.width(), params.height(), olive::core::PixelFormat::U8, 4,
|
||||||
|
params.pixel_aspect_ratio(), params.interlacing(), params.divider());
|
||||||
|
|
||||||
|
olive::AVFramePtr rgba_frame = olive::CreateAVFramePtr();
|
||||||
|
rgba_frame->format = AV_PIX_FMT_RGBA;
|
||||||
|
rgba_frame->width = params.width();
|
||||||
|
rgba_frame->height = params.height();
|
||||||
|
if (av_frame_get_buffer(rgba_frame.get(), 0) < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int linesize_pixels =
|
||||||
|
BytesToPixels(rgba_frame->linesize[0], rgba_params);
|
||||||
|
texture->renderer()->DownloadFromTexture(texture->id(), rgba_params,
|
||||||
|
rgba_frame->data[0],
|
||||||
|
linesize_pixels);
|
||||||
|
|
||||||
|
olive::AVFramePtr dst = olive::CreateAVFramePtr();
|
||||||
|
dst->format = pix_fmt;
|
||||||
|
dst->width = params.width();
|
||||||
|
dst->height = params.height();
|
||||||
|
if (av_frame_get_buffer(dst.get(), 0) < 0) {
|
||||||
|
return rgba_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwsContext *sws_ctx = sws_getContext(
|
||||||
|
rgba_frame->width, rgba_frame->height,
|
||||||
|
static_cast<AVPixelFormat>(rgba_frame->format),
|
||||||
|
dst->width, dst->height, pix_fmt, SWS_POINT,
|
||||||
|
nullptr, nullptr, nullptr);
|
||||||
|
if (!sws_ctx) {
|
||||||
|
return rgba_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
sws_scale(sws_ctx, rgba_frame->data, rgba_frame->linesize, 0,
|
||||||
|
rgba_frame->height, dst->data, dst->linesize);
|
||||||
|
sws_freeContext(sws_ctx);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static olive::AVFramePtr ConvertPackedFloatFrame(olive::AVFramePtr src,
|
||||||
|
AVPixelFormat dst_fmt)
|
||||||
|
{
|
||||||
|
if (!src || !src->data[0]) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const int src_channels =
|
||||||
|
PackedFloatChannels(static_cast<AVPixelFormat>(src->format));
|
||||||
|
if (src_channels == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dst_channels = 0;
|
||||||
|
int bytes_per_component = 0;
|
||||||
|
if (!PackedDstInfo(dst_fmt, &dst_channels, &bytes_per_component)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
olive::AVFramePtr dst = olive::CreateAVFramePtr();
|
||||||
|
dst->format = dst_fmt;
|
||||||
|
dst->width = src->width;
|
||||||
|
dst->height = src->height;
|
||||||
|
if (av_frame_get_buffer(dst.get(), 0) < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto clamp01 = [](float v) -> float {
|
||||||
|
return std::clamp(v, 0.0f, 1.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int y = 0; y < src->height; ++y) {
|
||||||
|
const float *src_row = reinterpret_cast<const float *>(
|
||||||
|
src->data[0] + y * src->linesize[0]);
|
||||||
|
uint8_t *dst_row = dst->data[0] + y * dst->linesize[0];
|
||||||
|
|
||||||
|
if (bytes_per_component == 2) {
|
||||||
|
auto *dst_row_u16 = reinterpret_cast<uint16_t *>(dst_row);
|
||||||
|
for (int x = 0; x < src->width; ++x) {
|
||||||
|
const float *pix = src_row + x * src_channels;
|
||||||
|
float r = pix[0];
|
||||||
|
float g = (src_channels > 1) ? pix[1] : r;
|
||||||
|
float b = (src_channels > 2) ? pix[2] : r;
|
||||||
|
float a = (src_channels > 3) ? pix[3] : 1.0f;
|
||||||
|
if (dst_channels == 1) {
|
||||||
|
float luma = 0.2126f * r + 0.7152f * g + 0.0722f * b;
|
||||||
|
dst_row_u16[x] = static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(luma) * 65535.0f));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dst_row_u16[x * dst_channels + 0] =
|
||||||
|
static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(r) * 65535.0f));
|
||||||
|
dst_row_u16[x * dst_channels + 1] =
|
||||||
|
static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(g) * 65535.0f));
|
||||||
|
dst_row_u16[x * dst_channels + 2] =
|
||||||
|
static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(b) * 65535.0f));
|
||||||
|
if (dst_channels == 4) {
|
||||||
|
dst_row_u16[x * dst_channels + 3] =
|
||||||
|
static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(a) * 65535.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int x = 0; x < src->width; ++x) {
|
||||||
|
const float *pix = src_row + x * src_channels;
|
||||||
|
float r = pix[0];
|
||||||
|
float g = (src_channels > 1) ? pix[1] : r;
|
||||||
|
float b = (src_channels > 2) ? pix[2] : r;
|
||||||
|
float a = (src_channels > 3) ? pix[3] : 1.0f;
|
||||||
|
if (dst_channels == 1) {
|
||||||
|
float luma = 0.2126f * r + 0.7152f * g + 0.0722f * b;
|
||||||
|
dst_row[x] = static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(luma) * 255.0f));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dst_row[x * dst_channels + 0] =
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(r) * 255.0f));
|
||||||
|
dst_row[x * dst_channels + 1] =
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(g) * 255.0f));
|
||||||
|
dst_row[x * dst_channels + 2] =
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(b) * 255.0f));
|
||||||
|
if (dst_channels == 4) {
|
||||||
|
dst_row[x * dst_channels + 3] =
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(a) * 255.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &olive::plugin::OliveClipInstance::getUnmappedBitDepth() const
|
const std::string &olive::plugin::OliveClipInstance::getUnmappedBitDepth() const
|
||||||
@@ -125,14 +360,29 @@ const std::string &olive::plugin::OliveClipInstance::getFieldOrder() const
|
|||||||
bool olive::plugin::OliveClipInstance::getConnected() const
|
bool olive::plugin::OliveClipInstance::getConnected() const
|
||||||
{
|
{
|
||||||
if (name_ == kOfxImageEffectOutputClipName) {
|
if (name_ == kOfxImageEffectOutputClipName) {
|
||||||
return true;
|
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
||||||
|
if (!output_textures_.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (auto it = images_.cbegin(); it != images_.cend(); ++it) {
|
||||||
|
if (it.value()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
||||||
if (!input_textures_.isEmpty()) {
|
if (!input_textures_.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return !images_.isEmpty();
|
for (auto it = images_.cbegin(); it != images_.cend(); ++it) {
|
||||||
|
if (it.value()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
double olive::plugin::OliveClipInstance::getUnmappedFrameRate() const
|
double olive::plugin::OliveClipInstance::getUnmappedFrameRate() const
|
||||||
{
|
{
|
||||||
@@ -227,7 +477,7 @@ OfxRectD
|
|||||||
olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const
|
olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const
|
||||||
{
|
{
|
||||||
if (regionOfDefinitions_.contains(time)) {
|
if (regionOfDefinitions_.contains(time)) {
|
||||||
return regionOfDefinitions_[time];
|
return regionOfDefinitions_.value(time);
|
||||||
}
|
}
|
||||||
OfxRectD regionOfDefinition;
|
OfxRectD regionOfDefinition;
|
||||||
regionOfDefinition.x1 = regionOfDefinition.y1 = 0;
|
regionOfDefinition.x1 = regionOfDefinition.y1 = 0;
|
||||||
@@ -251,6 +501,7 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
VideoParams incoming = texture->params();
|
VideoParams incoming = texture->params();
|
||||||
|
// AI wrote this. Why?
|
||||||
if (params_.format() != PixelFormat::INVALID &&
|
if (params_.format() != PixelFormat::INVALID &&
|
||||||
params_.channel_count() > 0) {
|
params_.channel_count() > 0) {
|
||||||
incoming.set_format(params_.format());
|
incoming.set_format(params_.format());
|
||||||
@@ -264,7 +515,7 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
|
|
||||||
AVFramePtr frame = texture->frame();
|
AVFramePtr frame = texture->frame();
|
||||||
if (!frame || !frame->data[0]) {
|
if (!frame || !frame->data[0]) {
|
||||||
return;
|
frame = ReadbackTextureToFrame(texture, params_);
|
||||||
}
|
}
|
||||||
AVPixelFormat expected_fmt =
|
AVPixelFormat expected_fmt =
|
||||||
FFmpegUtils::GetFFmpegPixelFormat(params_.format(),
|
FFmpegUtils::GetFFmpegPixelFormat(params_.format(),
|
||||||
@@ -295,10 +546,23 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!frame || !frame->data[0]) {
|
||||||
|
std::memset(dst, 0, image->row_bytes() * image->height());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AVFramePtr src_frame = frame;
|
AVFramePtr src_frame = frame;
|
||||||
if (frame->format != expected_fmt ||
|
if (frame->format != expected_fmt ||
|
||||||
frame->width != params_.width() ||
|
frame->width != params_.width() ||
|
||||||
frame->height != params_.height()) {
|
frame->height != params_.height()) {
|
||||||
|
if (PackedFloatChannels(static_cast<AVPixelFormat>(frame->format)) > 0) {
|
||||||
|
AVFramePtr converted =
|
||||||
|
ConvertPackedFloatFrame(frame, expected_fmt);
|
||||||
|
if (converted) {
|
||||||
|
src_frame = converted;
|
||||||
|
goto copy_pixels;
|
||||||
|
}
|
||||||
|
}
|
||||||
AVFramePtr converted = CreateAVFramePtr();
|
AVFramePtr converted = CreateAVFramePtr();
|
||||||
converted->format = expected_fmt;
|
converted->format = expected_fmt;
|
||||||
converted->width = params_.width();
|
converted->width = params_.width();
|
||||||
@@ -324,6 +588,7 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
src_frame = converted;
|
src_frame = converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy_pixels:
|
||||||
int bytes_per_component = params_.format().byte_count();
|
int bytes_per_component = params_.format().byte_count();
|
||||||
int bytes_per_row = params_.width() * params_.channel_count() *
|
int bytes_per_row = params_.width() * params_.channel_count() *
|
||||||
bytes_per_component;
|
bytes_per_component;
|
||||||
@@ -340,7 +605,7 @@ void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void olive::plugin::OliveClipInstance::setOutputTexture(Texture *texture,
|
void olive::plugin::OliveClipInstance::setOutputTexture(TexturePtr texture,
|
||||||
OfxTime time)
|
OfxTime time)
|
||||||
{
|
{
|
||||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
||||||
@@ -361,12 +626,12 @@ olive::plugin::OliveClipInstance::loadTexture(OfxTime time, const char *format,
|
|||||||
{
|
{
|
||||||
(void)format;
|
(void)format;
|
||||||
|
|
||||||
Texture *gl_texture = nullptr;
|
TexturePtr gl_texture = nullptr;
|
||||||
if (isOutput()) {
|
if (isOutput()) {
|
||||||
gl_texture = output_textures_.value(time, nullptr);
|
gl_texture = output_textures_.value(time, nullptr);
|
||||||
} else {
|
} else {
|
||||||
TexturePtr input = input_textures_.value(time);
|
TexturePtr input = input_textures_.value(time);
|
||||||
gl_texture = input ? input.get() : nullptr;
|
gl_texture = input ? input : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gl_texture || gl_texture->IsDummy() || !gl_texture->id().isValid()) {
|
if (!gl_texture || gl_texture->IsDummy() || !gl_texture->id().isValid()) {
|
||||||
@@ -394,7 +659,7 @@ olive::plugin::OliveClipInstance::loadTexture(OfxTime time, const char *format,
|
|||||||
params_.width() * params_.channel_count() * params_.format().byte_count();
|
params_.width() * params_.channel_count() * params_.format().byte_count();
|
||||||
const std::string &field = getFieldOrder();
|
const std::string &field = getFieldOrder();
|
||||||
const std::string unique_id = std::to_string(
|
const std::string unique_id = std::to_string(
|
||||||
reinterpret_cast<uintptr_t>(gl_texture)) + "_" +
|
reinterpret_cast<uintptr_t>(gl_texture.get())) + "_" +
|
||||||
std::to_string(static_cast<long long>(time));
|
std::to_string(static_cast<long long>(time));
|
||||||
|
|
||||||
const int texture_id = gl_texture->id().value<GLuint>();
|
const int texture_id = gl_texture->id().value<GLuint>();
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public:
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
void setInputTexture(TexturePtr texture, OfxTime time);
|
void setInputTexture(TexturePtr texture, OfxTime time);
|
||||||
void setOutputTexture(Texture *texture, OfxTime time);
|
void setOutputTexture(TexturePtr texture, OfxTime time);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VideoParams params_;
|
VideoParams params_;
|
||||||
@@ -86,7 +86,7 @@ private:
|
|||||||
QMap<OfxTime,std::shared_ptr<Image>> images_;
|
QMap<OfxTime,std::shared_ptr<Image>> images_;
|
||||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
||||||
QMap<OfxTime, TexturePtr> input_textures_;
|
QMap<OfxTime, TexturePtr> input_textures_;
|
||||||
QMap<OfxTime, Texture *> output_textures_;
|
QMap<OfxTime, TexturePtr> output_textures_;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
#include <ofxhPluginCache.h>
|
#include <ofxhPluginCache.h>
|
||||||
#include <ofxhBinary.h>
|
#include <ofxhBinary.h>
|
||||||
|
|
||||||
@@ -108,14 +109,6 @@ void olive::plugin::loadPlugins(QString path)
|
|||||||
}
|
}
|
||||||
OliveHost::~OliveHost()
|
OliveHost::~OliveHost()
|
||||||
{
|
{
|
||||||
for(auto& descriptor:descriptors_){
|
|
||||||
delete descriptor;
|
|
||||||
descriptor=nullptr;
|
|
||||||
}
|
|
||||||
for(auto& instance:instances_){
|
|
||||||
delete instance;
|
|
||||||
instance=nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,45 +117,37 @@ void OliveHost::destroyInstance(OFX::Host::ImageEffect::Instance* instance)
|
|||||||
if (!instance) {
|
if (!instance) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (instances_.contains(instance))
|
for (auto it = instances_.begin(); it != instances_.end(); ++it) {
|
||||||
{
|
if (it->get() == instance) {
|
||||||
instances_.removeOne(instance);
|
instances_.erase(it);
|
||||||
delete instance;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImageEffect::Descriptor *
|
std::shared_ptr<OFX::Host::ImageEffect::Descriptor>
|
||||||
OliveHost::makeDescriptor(ImageEffect::ImageEffectPlugin* plugin)
|
OliveHost::makeDescriptor(ImageEffect::ImageEffectPlugin *plugin)
|
||||||
{
|
{
|
||||||
ImageEffect::Descriptor* desc = new ImageEffect::Descriptor(plugin);
|
std::shared_ptr<OFX::Host::ImageEffect::Descriptor> desc =
|
||||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
std::make_shared<ImageEffect::Descriptor>(plugin);
|
||||||
desc->getProps().setStringProperty(kOfxImageEffectPropOpenGLRenderSupported,
|
descriptors_.append(std::shared_ptr<ImageEffect::Descriptor>(desc));
|
||||||
"true");
|
|
||||||
#endif
|
|
||||||
descriptors_.append(desc);
|
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
ImageEffect::Descriptor *
|
std::shared_ptr<OFX::Host::ImageEffect::Descriptor>
|
||||||
OliveHost::makeDescriptor(const ImageEffect::Descriptor &rootContext,
|
OliveHost::makeDescriptor(const ImageEffect::Descriptor &rootContext,
|
||||||
ImageEffect::ImageEffectPlugin *plugin)
|
ImageEffect::ImageEffectPlugin *plugin)
|
||||||
{
|
{
|
||||||
ImageEffect::Descriptor* desc = new ImageEffect::Descriptor(rootContext,plugin);
|
std::shared_ptr<OFX::Host::ImageEffect::Descriptor> desc =
|
||||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
std::make_shared<ImageEffect::Descriptor>(rootContext, plugin);
|
||||||
desc->getProps().setStringProperty(kOfxImageEffectPropOpenGLRenderSupported,
|
descriptors_.append(std::shared_ptr<ImageEffect::Descriptor>(desc));
|
||||||
"true");
|
|
||||||
#endif
|
|
||||||
descriptors_.append(desc);
|
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
ImageEffect::Descriptor *
|
std::shared_ptr<OFX::Host::ImageEffect::Descriptor>
|
||||||
OliveHost::makeDescriptor(const std::string &bundlePath,
|
OliveHost::makeDescriptor(const std::string &bundlePath,
|
||||||
ImageEffect::ImageEffectPlugin *plugin)
|
ImageEffect::ImageEffectPlugin *plugin)
|
||||||
{
|
{
|
||||||
ImageEffect::Descriptor* desc = new ImageEffect::Descriptor(bundlePath, plugin);
|
std::shared_ptr<OFX::Host::ImageEffect::Descriptor> desc =
|
||||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
std::make_shared<ImageEffect::Descriptor>(bundlePath, plugin);
|
||||||
desc->getProps().setStringProperty(kOfxImageEffectPropOpenGLRenderSupported,
|
descriptors_.append(std::shared_ptr<ImageEffect::Descriptor>(desc));
|
||||||
"true");
|
|
||||||
#endif
|
|
||||||
descriptors_.append(desc);
|
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +162,7 @@ ImageEffect::Instance* OliveHost::newInstance(void *clientData,
|
|||||||
instance->setNode(
|
instance->setNode(
|
||||||
std::shared_ptr<PluginNode>(node, [](PluginNode *) {}));
|
std::shared_ptr<PluginNode>(node, [](PluginNode *) {}));
|
||||||
}
|
}
|
||||||
instances_.append(instance);
|
instances_.append(std::shared_ptr<OlivePluginInstance>(instance));
|
||||||
return instance;
|
return instance;
|
||||||
};
|
};
|
||||||
OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id, const char *format,
|
OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id, const char *format,
|
||||||
@@ -217,7 +202,7 @@ OfxStatus olive::plugin::OliveHost::vmessage(const char *type, const char *id, c
|
|||||||
|
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
|
// TODO: Persistent messages shouldn't use pop-up window.
|
||||||
OfxStatus olive::plugin::OliveHost::setPersistentMessage(
|
OfxStatus olive::plugin::OliveHost::setPersistentMessage(
|
||||||
const char *type, const char *id, const char *format, va_list args)
|
const char *type, const char *id, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <any>
|
#include <any>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
#include <qlist.h>
|
#include <qlist.h>
|
||||||
namespace olive {
|
namespace olive {
|
||||||
namespace plugin {
|
namespace plugin {
|
||||||
@@ -70,16 +71,16 @@ public:
|
|||||||
const std::string& context) override;
|
const std::string& context) override;
|
||||||
|
|
||||||
|
|
||||||
OFX::Host::ImageEffect::Descriptor *makeDescriptor(
|
std::shared_ptr<OFX::Host::ImageEffect::Descriptor> makeDescriptor(
|
||||||
OFX::Host::ImageEffect::ImageEffectPlugin* plugin) override;
|
OFX::Host::ImageEffect::ImageEffectPlugin* plugin) override;
|
||||||
|
|
||||||
OFX::Host::ImageEffect::Descriptor *makeDescriptor(
|
std::shared_ptr<OFX::Host::ImageEffect::Descriptor>
|
||||||
const OFX::Host::ImageEffect::Descriptor &rootContext,
|
makeDescriptor(const OFX::Host::ImageEffect::Descriptor &rootContext,
|
||||||
OFX::Host::ImageEffect::ImageEffectPlugin *plugin) override;
|
OFX::Host::ImageEffect::ImageEffectPlugin *plugin) override;
|
||||||
|
|
||||||
OFX::Host::ImageEffect::Descriptor *makeDescriptor(
|
std::shared_ptr<OFX::Host::ImageEffect::Descriptor>
|
||||||
const std::string &bundlePath,
|
makeDescriptor(const std::string &bundlePath,
|
||||||
OFX::Host::ImageEffect::ImageEffectPlugin *plugin) override;
|
OFX::Host::ImageEffect::ImageEffectPlugin *plugin) override;
|
||||||
/// vmessage
|
/// vmessage
|
||||||
virtual OfxStatus vmessage(const char *type, const char *id,
|
virtual OfxStatus vmessage(const char *type, const char *id,
|
||||||
const char *format, va_list args);
|
const char *format, va_list args);
|
||||||
@@ -98,8 +99,8 @@ public:
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
private:
|
private:
|
||||||
QList<OFX::Host::ImageEffect::Descriptor*> descriptors_;
|
QList<std::shared_ptr<OFX::Host::ImageEffect::Descriptor>> descriptors_;
|
||||||
QList<OFX::Host::ImageEffect::Instance*> instances_;
|
QList<std::shared_ptr<OFX::Host::ImageEffect::Instance>> instances_;
|
||||||
QList<HostPersistentMessage> persistent_messages_;
|
QList<HostPersistentMessage> persistent_messages_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,11 @@
|
|||||||
#include "panel/timeline/timeline.h"
|
#include "panel/timeline/timeline.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <qmessagebox.h>
|
#include <QCoreApplication>
|
||||||
#include <qobject.h>
|
#include <QMessageBox>
|
||||||
|
#include <QMetaObject>
|
||||||
|
#include <QThread>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@@ -48,6 +48,35 @@ const std::string kImageFieldNoneStr(kOfxImageFieldNone);
|
|||||||
const std::string kImageFieldUpperStr(kOfxImageFieldUpper);
|
const std::string kImageFieldUpperStr(kOfxImageFieldUpper);
|
||||||
const std::string kImageFieldLowerStr(kOfxImageFieldLower);
|
const std::string kImageFieldLowerStr(kOfxImageFieldLower);
|
||||||
|
|
||||||
|
QString FormatOfxMessage(const char *format, va_list args)
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
va_list args_copy;
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
const int needed = vsnprintf(buffer, sizeof(buffer), format, args_copy);
|
||||||
|
va_end(args_copy);
|
||||||
|
if (needed < 0) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
if (needed < static_cast<int>(sizeof(buffer))) {
|
||||||
|
return QString::fromUtf8(buffer);
|
||||||
|
}
|
||||||
|
QByteArray dynamic_buffer(needed + 1, 0);
|
||||||
|
const int written = vsnprintf(dynamic_buffer.data(), dynamic_buffer.size(), format, args);
|
||||||
|
if (written < 0) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return QString::fromUtf8(dynamic_buffer.constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsGuiThread()
|
||||||
|
{
|
||||||
|
if (auto *app = QCoreApplication::instance()) {
|
||||||
|
return QThread::currentThread() == app->thread();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string &FieldOrderForParams(const VideoParams ¶ms)
|
const std::string &FieldOrderForParams(const VideoParams ¶ms)
|
||||||
{
|
{
|
||||||
switch (params.interlacing()) {
|
switch (params.interlacing()) {
|
||||||
@@ -134,75 +163,101 @@ const std::string &OlivePluginInstance::getDefaultOutputFielding() const
|
|||||||
OfxStatus OlivePluginInstance::vmessage(const char *type, const char *id,
|
OfxStatus OlivePluginInstance::vmessage(const char *type, const char *id,
|
||||||
const char *format, va_list args)
|
const char *format, va_list args)
|
||||||
{
|
{
|
||||||
char *buffer = new char[1024];
|
const QString message = FormatOfxMessage(format, args);
|
||||||
|
if (message.isEmpty()) {
|
||||||
memset(buffer, 0, 1024 * sizeof(char));
|
return kOfxStatFailed;
|
||||||
vsprintf(buffer, format, args);
|
|
||||||
|
|
||||||
QString message(buffer);
|
|
||||||
|
|
||||||
delete[] buffer;
|
|
||||||
|
|
||||||
if (strncmp(type, kOfxMessageQuestion, strlen(kOfxMessageQuestion))) {
|
|
||||||
auto ret = QMessageBox::information(
|
|
||||||
nullptr, "", message, QMessageBox::Ok, QMessageBox::Cancel);
|
|
||||||
|
|
||||||
if (ret == QMessageBox::Ok) {
|
|
||||||
return kOfxStatReplyYes;
|
|
||||||
} else {
|
|
||||||
return kOfxStatReplyNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
QMessageBox::information(nullptr, "", message);
|
|
||||||
return kOfxStatOK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool is_question =
|
||||||
|
strncmp(type, kOfxMessageQuestion, strlen(kOfxMessageQuestion)) == 0;
|
||||||
|
OfxStatus result = kOfxStatOK;
|
||||||
|
auto show_message = [&]() {
|
||||||
|
if (is_question) {
|
||||||
|
const auto ret = QMessageBox::question(
|
||||||
|
nullptr, "", message, QMessageBox::Ok, QMessageBox::Cancel);
|
||||||
|
result = (ret == QMessageBox::Ok) ? kOfxStatReplyYes : kOfxStatReplyNo;
|
||||||
|
} else {
|
||||||
|
QMessageBox::information(nullptr, "", message);
|
||||||
|
result = kOfxStatOK;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (IsGuiThread()) {
|
||||||
|
show_message();
|
||||||
|
} else if (auto *app = QCoreApplication::instance()) {
|
||||||
|
if (is_question) {
|
||||||
|
QMetaObject::invokeMethod(app, show_message, Qt::BlockingQueuedConnection);
|
||||||
|
} else {
|
||||||
|
QMetaObject::invokeMethod(app, show_message, Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
} else if (is_question) {
|
||||||
|
result = kOfxStatReplyNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
OfxStatus OlivePluginInstance::setPersistentMessage(const char *type, const char *id,
|
OfxStatus OlivePluginInstance::setPersistentMessage(const char *type, const char *id,
|
||||||
const char *format, va_list args)
|
const char *format, va_list args)
|
||||||
{
|
{
|
||||||
char *buffer = new char[1024];
|
const QString message = FormatOfxMessage(format, args);
|
||||||
|
if (message.isEmpty()) {
|
||||||
memset(buffer, 0, 1024 * sizeof(char));
|
|
||||||
int ret = vsprintf(buffer, format, args);
|
|
||||||
if (ret < 0) {
|
|
||||||
return kOfxStatFailed;
|
return kOfxStatFailed;
|
||||||
}
|
}
|
||||||
QString message(buffer);
|
|
||||||
|
|
||||||
delete[] buffer;
|
|
||||||
|
|
||||||
|
ErrorType error_type;
|
||||||
// If This is a error message
|
// If This is a error message
|
||||||
if (strncmp(type, kOfxMessageError, strlen(kOfxMessageError)) == 0) {
|
if (strncmp(type, kOfxMessageError, strlen(kOfxMessageError)) == 0) {
|
||||||
persistentErrors_.append({ ErrorType::Error, message });
|
error_type = ErrorType::Error;
|
||||||
QMessageBox::critical(nullptr, "", message);
|
|
||||||
// TODO: tell the shell to show the error
|
|
||||||
}
|
}
|
||||||
// A warning
|
// A warning
|
||||||
else if (strncmp(type, kOfxMessageWarning, strlen(kOfxMessageError)) == 0) {
|
else if (strncmp(type, kOfxMessageWarning, strlen(kOfxMessageWarning)) == 0) {
|
||||||
persistentErrors_.append({ ErrorType::Warning, message });
|
error_type = ErrorType::Warning;
|
||||||
QMessageBox::warning(nullptr, "", message);
|
|
||||||
// TODO: tell the shell to show the warning
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// A simple information
|
// A simple information
|
||||||
else if (strncmp(type, kOfxMessageMessage, strlen(kOfxMessageError)) == 0) {
|
else if (strncmp(type, kOfxMessageMessage, strlen(kOfxMessageMessage)) == 0) {
|
||||||
persistentErrors_.append({ ErrorType::Message, message });
|
error_type = ErrorType::Message;
|
||||||
QMessageBox::information(nullptr, "", message);
|
|
||||||
} else {
|
} else {
|
||||||
return kOfxStatFailed;
|
return kOfxStatFailed;
|
||||||
}
|
}
|
||||||
if (node_) {
|
|
||||||
emit node_->MessageCountChanged();
|
auto update_ui = [this, error_type, message]() {
|
||||||
|
persistentErrors_.append({ error_type, message });
|
||||||
|
switch (error_type) {
|
||||||
|
case ErrorType::Error:
|
||||||
|
QMessageBox::critical(nullptr, "", message);
|
||||||
|
break;
|
||||||
|
case ErrorType::Warning:
|
||||||
|
QMessageBox::warning(nullptr, "", message);
|
||||||
|
break;
|
||||||
|
case ErrorType::Message:
|
||||||
|
QMessageBox::information(nullptr, "", message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (node_) {
|
||||||
|
emit node_->MessageCountChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (IsGuiThread()) {
|
||||||
|
update_ui();
|
||||||
|
} else if (auto *app = QCoreApplication::instance()) {
|
||||||
|
QMetaObject::invokeMethod(app, update_ui, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
OfxStatus OlivePluginInstance::clearPersistentMessage()
|
OfxStatus OlivePluginInstance::clearPersistentMessage()
|
||||||
{
|
{
|
||||||
persistentErrors_.clear();
|
auto clear_ui = [this]() {
|
||||||
// TODO: tell the shell to remove message.
|
persistentErrors_.clear();
|
||||||
if (node_) {
|
// TODO: tell the shell to remove message.
|
||||||
emit node_->MessageCountChanged();
|
if (node_) {
|
||||||
|
emit node_->MessageCountChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (IsGuiThread()) {
|
||||||
|
clear_ui();
|
||||||
|
} else if (auto *app = QCoreApplication::instance()) {
|
||||||
|
QMetaObject::invokeMethod(app, clear_ui, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
return kOfxStatOK;
|
return kOfxStatOK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,8 +65,10 @@ protected:
|
|||||||
int value_ = 0;
|
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),
|
: OFX::Host::Param::IntegerInstance(descriptor)
|
||||||
OFX::Host::Param::IntegerInstance(_descriptor){}
|
, _node(node)
|
||||||
|
, _descriptor(descriptor)
|
||||||
|
{}
|
||||||
OfxStatus get(int &a)
|
OfxStatus get(int &a)
|
||||||
{
|
{
|
||||||
if (!_node) {
|
if (!_node) {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define PLUGINJOB_H
|
#define PLUGINJOB_H
|
||||||
#include "acceleratedjob.h"
|
#include "acceleratedjob.h"
|
||||||
#include "pluginSupport/OlivePluginInstance.h"
|
#include "pluginSupport/OlivePluginInstance.h"
|
||||||
|
#include "olive/core/util/rational.h"
|
||||||
|
|
||||||
#include <any>
|
#include <any>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -31,13 +32,20 @@ namespace plugin {
|
|||||||
class PluginJob :public AcceleratedJob{
|
class PluginJob :public AcceleratedJob{
|
||||||
public:
|
public:
|
||||||
explicit PluginJob(const OFX::Host::ImageEffect::Instance* pluginInstance,
|
explicit PluginJob(const OFX::Host::ImageEffect::Instance* pluginInstance,
|
||||||
const PluginNode* node, NodeValueRow row)
|
const PluginNode* node, NodeValueRow row,
|
||||||
|
const olive::core::rational &time)
|
||||||
: AcceleratedJob()
|
: AcceleratedJob()
|
||||||
|
, time_seconds_(time.toDouble())
|
||||||
{
|
{
|
||||||
this->pluginInstance_ = pluginInstance;
|
this->pluginInstance_ = pluginInstance;
|
||||||
this->node_=node;
|
this->node_=node;
|
||||||
Insert(row);
|
Insert(row);
|
||||||
}
|
}
|
||||||
|
explicit PluginJob(const OFX::Host::ImageEffect::Instance* pluginInstance,
|
||||||
|
const PluginNode* node, NodeValueRow row)
|
||||||
|
: PluginJob(pluginInstance, node, row, olive::core::rational(0))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
PluginNode *node() const {
|
PluginNode *node() const {
|
||||||
return const_cast<PluginNode *>(node_);
|
return const_cast<PluginNode *>(node_);
|
||||||
@@ -47,6 +55,10 @@ public:
|
|||||||
return const_cast<OFX::Host::ImageEffect::Instance*>(pluginInstance_);
|
return const_cast<OFX::Host::ImageEffect::Instance*>(pluginInstance_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double time_seconds() const {
|
||||||
|
return time_seconds_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const OFX::Host::ImageEffect::Instance *pluginInstance_=nullptr;
|
const OFX::Host::ImageEffect::Instance *pluginInstance_=nullptr;
|
||||||
|
|
||||||
@@ -55,6 +67,7 @@ private:
|
|||||||
QHash<QString, std::any> params;
|
QHash<QString, std::any> params;
|
||||||
|
|
||||||
const PluginNode *node_=nullptr;
|
const PluginNode *node_=nullptr;
|
||||||
|
double time_seconds_ = 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // plugin
|
} // plugin
|
||||||
|
|||||||
@@ -151,8 +151,9 @@ void OpenGLRenderer::DestroyInternal()
|
|||||||
if (context_) {
|
if (context_) {
|
||||||
GL_PREAMBLE;
|
GL_PREAMBLE;
|
||||||
|
|
||||||
// Delete framebuffer
|
if (functions_ && framebuffer_) {
|
||||||
functions_->glDeleteFramebuffers(1, &framebuffer_);
|
functions_->glDeleteFramebuffers(1, &framebuffer_);
|
||||||
|
}
|
||||||
framebuffer_ = 0;
|
framebuffer_ = 0;
|
||||||
|
|
||||||
// Delete context if it belongs to us
|
// Delete context if it belongs to us
|
||||||
@@ -160,6 +161,7 @@ void OpenGLRenderer::DestroyInternal()
|
|||||||
delete context_;
|
delete context_;
|
||||||
}
|
}
|
||||||
context_ = nullptr;
|
context_ = nullptr;
|
||||||
|
functions_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,11 +337,28 @@ void OpenGLRenderer::DownloadFromTexture(const QVariant &id,
|
|||||||
{
|
{
|
||||||
GL_PREAMBLE;
|
GL_PREAMBLE;
|
||||||
|
|
||||||
|
if (!EnsureContextCurrent(__FUNCTION__)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint texture_id = id.value<GLuint>();
|
||||||
|
if (!texture_id || !functions_->glIsTexture(texture_id)) {
|
||||||
|
qWarning() << "DownloadFromTexture called with invalid texture";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GLint current_tex;
|
GLint current_tex;
|
||||||
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex);
|
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex);
|
||||||
|
|
||||||
AttachTextureAsDestination(id);
|
AttachTextureAsDestination(id);
|
||||||
|
|
||||||
|
GLenum status = functions_->glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
qWarning() << "DownloadFromTexture framebuffer incomplete" << status;
|
||||||
|
DetachTextureAsDestination();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, linesize);
|
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, linesize);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -921,4 +940,39 @@ GLuint OpenGLRenderer::CompileShader(GLenum type, const QString &code)
|
|||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OpenGLRenderer::EnsureContextCurrent(const char *caller)
|
||||||
|
{
|
||||||
|
if (!context_) {
|
||||||
|
qWarning() << caller << "called without an OpenGL context";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QOpenGLContext::currentContext() != context_) {
|
||||||
|
if (context_->parent() == this && surface_.isValid()) {
|
||||||
|
if (!context_->makeCurrent(&surface_)) {
|
||||||
|
qWarning() << caller << "failed to make context current";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning() << caller << "OpenGL context not current";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!functions_) {
|
||||||
|
functions_ = context_->functions();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!functions_) {
|
||||||
|
qWarning() << caller << "OpenGL functions not available";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!framebuffer_) {
|
||||||
|
functions_->glGenFramebuffers(1, &framebuffer_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,6 +99,8 @@ private:
|
|||||||
|
|
||||||
static GLenum GetPixelFormat(int channel_count);
|
static GLenum GetPixelFormat(int channel_count);
|
||||||
|
|
||||||
|
bool EnsureContextCurrent(const char *caller);
|
||||||
|
|
||||||
void PrepareInputTexture(GLenum target, Texture::Interpolation interp);
|
void PrepareInputTexture(GLenum target, Texture::Interpolation interp);
|
||||||
|
|
||||||
void ClearDestinationInternal(double r = 0.0, double g = 0.0,
|
void ClearDestinationInternal(double r = 0.0, double g = 0.0,
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
//
|
//
|
||||||
// Created by mikesolar on 25-10-19.
|
// Created by mikesolar on 25-10-19.
|
||||||
//
|
//
|
||||||
|
#include "render/texture.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <qtypes.h>
|
#include <qtypes.h>
|
||||||
@@ -31,6 +34,7 @@
|
|||||||
#include "common/ffmpegutils.h"
|
#include "common/ffmpegutils.h"
|
||||||
#include "ofxImageEffect.h"
|
#include "ofxImageEffect.h"
|
||||||
#include "ofxhUtilities.h"
|
#include "ofxhUtilities.h"
|
||||||
|
#include "ofxGPURender.h"
|
||||||
extern "C"{
|
extern "C"{
|
||||||
#include <libavutil/pixfmt.h>
|
#include <libavutil/pixfmt.h>
|
||||||
#include <libavutil/pixdesc.h>
|
#include <libavutil/pixdesc.h>
|
||||||
@@ -280,7 +284,7 @@ static const char *GetRenderFieldForParams(const olive::VideoParams ¶ms)
|
|||||||
return kOfxImageFieldNone;
|
return kOfxImageFieldNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
static olive::AVFramePtr ReadbackTextureToFrame(olive::Texture *texture,
|
static olive::AVFramePtr ReadbackTextureToFrame(olive::TexturePtr texture,
|
||||||
const olive::VideoParams ¶ms)
|
const olive::VideoParams ¶ms)
|
||||||
{
|
{
|
||||||
if (!texture || texture->IsDummy()) {
|
if (!texture || texture->IsDummy()) {
|
||||||
@@ -307,8 +311,11 @@ static olive::AVFramePtr ReadbackTextureToFrame(olive::Texture *texture,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (texture->renderer()) {
|
if (texture->renderer()) {
|
||||||
|
const int linesize_pixels =
|
||||||
|
olive::plugin::detail::BytesToPixels(frame->linesize[0],
|
||||||
|
params);
|
||||||
texture->renderer()->DownloadFromTexture(
|
texture->renderer()->DownloadFromTexture(
|
||||||
texture->id(), params, frame->data[0], frame->linesize[0]);
|
texture->id(), params, frame->data[0], linesize_pixels);
|
||||||
}
|
}
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
@@ -327,9 +334,11 @@ static olive::AVFramePtr ReadbackTextureToFrame(olive::Texture *texture,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (texture->renderer()) {
|
if (texture->renderer()) {
|
||||||
|
const int linesize_pixels =
|
||||||
|
olive::plugin::detail::BytesToPixels(rgba_frame->linesize[0],
|
||||||
|
rgba_params);
|
||||||
texture->renderer()->DownloadFromTexture(
|
texture->renderer()->DownloadFromTexture(
|
||||||
texture->id(), rgba_params, rgba_frame->data[0],
|
texture->id(), rgba_params, rgba_frame->data[0], linesize_pixels);
|
||||||
rgba_frame->linesize[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
olive::AVFramePtr dst = olive::CreateAVFramePtr();
|
olive::AVFramePtr dst = olive::CreateAVFramePtr();
|
||||||
@@ -356,6 +365,18 @@ static olive::AVFramePtr ReadbackTextureToFrame(olive::Texture *texture,
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int olive::plugin::detail::BytesToPixels(int byte_linesize,
|
||||||
|
const olive::VideoParams ¶ms)
|
||||||
|
{
|
||||||
|
const int bytes_per_pixel =
|
||||||
|
olive::VideoParams::GetBytesPerPixel(params.format(),
|
||||||
|
params.channel_count());
|
||||||
|
if (byte_linesize <= 0 || bytes_per_pixel <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return byte_linesize / bytes_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
static olive::AVFramePtr ConvertFrameIfNeeded(olive::AVFramePtr src,
|
static olive::AVFramePtr ConvertFrameIfNeeded(olive::AVFramePtr src,
|
||||||
const olive::VideoParams &dst_params)
|
const olive::VideoParams &dst_params)
|
||||||
{
|
{
|
||||||
@@ -382,6 +403,240 @@ static olive::AVFramePtr ConvertFrameIfNeeded(olive::AVFramePtr src,
|
|||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto float_channels = [](AVPixelFormat fmt) -> int {
|
||||||
|
switch (fmt) {
|
||||||
|
case AV_PIX_FMT_GRAYF32LE:
|
||||||
|
case AV_PIX_FMT_GRAYF32BE:
|
||||||
|
return 1;
|
||||||
|
case AV_PIX_FMT_RGBF32LE:
|
||||||
|
case AV_PIX_FMT_RGBF32BE:
|
||||||
|
return 3;
|
||||||
|
case AV_PIX_FMT_RGBAF32LE:
|
||||||
|
case AV_PIX_FMT_RGBAF32BE:
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto dst_packed_info = [](AVPixelFormat fmt, int *channels,
|
||||||
|
int *bytes_per_component) -> bool {
|
||||||
|
switch (fmt) {
|
||||||
|
case AV_PIX_FMT_GRAY8:
|
||||||
|
*channels = 1;
|
||||||
|
*bytes_per_component = 1;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_RGB24:
|
||||||
|
*channels = 3;
|
||||||
|
*bytes_per_component = 1;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_RGBA:
|
||||||
|
*channels = 4;
|
||||||
|
*bytes_per_component = 1;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_GRAY16LE:
|
||||||
|
*channels = 1;
|
||||||
|
*bytes_per_component = 2;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_RGB48LE:
|
||||||
|
*channels = 3;
|
||||||
|
*bytes_per_component = 2;
|
||||||
|
return true;
|
||||||
|
case AV_PIX_FMT_RGBA64LE:
|
||||||
|
*channels = 4;
|
||||||
|
*bytes_per_component = 2;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto float_dst_from_packed = [&](const olive::AVFramePtr &packed_src,
|
||||||
|
AVPixelFormat float_fmt,
|
||||||
|
const olive::AVFramePtr &float_dst) -> bool {
|
||||||
|
if (!packed_src || !float_dst || !packed_src->data[0] ||
|
||||||
|
!float_dst->data[0]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const int dst_channels = float_channels(float_fmt);
|
||||||
|
if (dst_channels == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int src_channels = 0;
|
||||||
|
int bytes_per_component = 0;
|
||||||
|
if (!dst_packed_info(static_cast<AVPixelFormat>(packed_src->format),
|
||||||
|
&src_channels, &bytes_per_component)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const float inv_scale =
|
||||||
|
(bytes_per_component == 2) ? (1.0f / 65535.0f)
|
||||||
|
: (1.0f / 255.0f);
|
||||||
|
for (int y = 0; y < packed_src->height; ++y) {
|
||||||
|
const uint8_t *src_row =
|
||||||
|
packed_src->data[0] + y * packed_src->linesize[0];
|
||||||
|
float *dst_row = reinterpret_cast<float *>(
|
||||||
|
float_dst->data[0] + y * float_dst->linesize[0]);
|
||||||
|
if (bytes_per_component == 2) {
|
||||||
|
const uint16_t *src_u16 =
|
||||||
|
reinterpret_cast<const uint16_t *>(src_row);
|
||||||
|
for (int x = 0; x < packed_src->width; ++x) {
|
||||||
|
const uint16_t *pix = src_u16 + x * src_channels;
|
||||||
|
float r = pix[0] * inv_scale;
|
||||||
|
float g = (src_channels > 1) ? pix[1] * inv_scale : r;
|
||||||
|
float b = (src_channels > 2) ? pix[2] * inv_scale : r;
|
||||||
|
float a = (src_channels > 3) ? pix[3] * inv_scale : 1.0f;
|
||||||
|
dst_row[x * dst_channels + 0] = r;
|
||||||
|
if (dst_channels > 1) {
|
||||||
|
dst_row[x * dst_channels + 1] = g;
|
||||||
|
}
|
||||||
|
if (dst_channels > 2) {
|
||||||
|
dst_row[x * dst_channels + 2] = b;
|
||||||
|
}
|
||||||
|
if (dst_channels > 3) {
|
||||||
|
dst_row[x * dst_channels + 3] = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int x = 0; x < packed_src->width; ++x) {
|
||||||
|
const uint8_t *pix = src_row + x * src_channels;
|
||||||
|
float r = pix[0] * inv_scale;
|
||||||
|
float g = (src_channels > 1) ? pix[1] * inv_scale : r;
|
||||||
|
float b = (src_channels > 2) ? pix[2] * inv_scale : r;
|
||||||
|
float a = (src_channels > 3) ? pix[3] * inv_scale : 1.0f;
|
||||||
|
dst_row[x * dst_channels + 0] = r;
|
||||||
|
if (dst_channels > 1) {
|
||||||
|
dst_row[x * dst_channels + 1] = g;
|
||||||
|
}
|
||||||
|
if (dst_channels > 2) {
|
||||||
|
dst_row[x * dst_channels + 2] = b;
|
||||||
|
}
|
||||||
|
if (dst_channels > 3) {
|
||||||
|
dst_row[x * dst_channels + 3] = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const int dst_float_channels = float_channels(dst_fmt);
|
||||||
|
if (dst_float_channels > 0) {
|
||||||
|
int src_channels = 0;
|
||||||
|
int bytes_per_component = 0;
|
||||||
|
if (dst_packed_info(static_cast<AVPixelFormat>(src->format),
|
||||||
|
&src_channels, &bytes_per_component)) {
|
||||||
|
if (float_dst_from_packed(src, dst_fmt, dst)) {
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
olive::AVFramePtr packed = olive::CreateAVFramePtr();
|
||||||
|
AVPixelFormat packed_fmt = (dst_float_channels == 4)
|
||||||
|
? AV_PIX_FMT_RGBA
|
||||||
|
: (dst_float_channels == 3)
|
||||||
|
? AV_PIX_FMT_RGB24
|
||||||
|
: AV_PIX_FMT_GRAY8;
|
||||||
|
packed->format = packed_fmt;
|
||||||
|
packed->width = dst->width;
|
||||||
|
packed->height = dst->height;
|
||||||
|
if (av_frame_get_buffer(packed.get(), 0) >= 0) {
|
||||||
|
SwsContext *pre_ctx = sws_getContext(
|
||||||
|
src->width, src->height,
|
||||||
|
static_cast<AVPixelFormat>(src->format),
|
||||||
|
packed->width, packed->height, packed_fmt, SWS_POINT,
|
||||||
|
nullptr, nullptr, nullptr);
|
||||||
|
if (pre_ctx) {
|
||||||
|
sws_scale(pre_ctx, src->data, src->linesize, 0, src->height,
|
||||||
|
packed->data, packed->linesize);
|
||||||
|
sws_freeContext(pre_ctx);
|
||||||
|
if (float_dst_from_packed(packed, dst_fmt, dst)) {
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto clamp01 = [](float v) -> float {
|
||||||
|
return std::clamp(v, 0.0f, 1.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
const int src_float_channels = float_channels(
|
||||||
|
static_cast<AVPixelFormat>(src->format));
|
||||||
|
if (src_float_channels > 0) {
|
||||||
|
int dst_channels = 0;
|
||||||
|
int bytes_per_component = 0;
|
||||||
|
if (dst_packed_info(dst_fmt, &dst_channels, &bytes_per_component) &&
|
||||||
|
src->data[0] && dst->data[0]) {
|
||||||
|
for (int y = 0; y < src->height; ++y) {
|
||||||
|
const float *src_row = reinterpret_cast<const float *>(
|
||||||
|
src->data[0] + y * src->linesize[0]);
|
||||||
|
uint8_t *dst_row = dst->data[0] + y * dst->linesize[0];
|
||||||
|
if (bytes_per_component == 2) {
|
||||||
|
auto *dst_row_u16 =
|
||||||
|
reinterpret_cast<uint16_t *>(dst_row);
|
||||||
|
for (int x = 0; x < src->width; ++x) {
|
||||||
|
const float *pix =
|
||||||
|
src_row + x * src_float_channels;
|
||||||
|
float r = pix[0];
|
||||||
|
float g = (src_float_channels > 1) ? pix[1] : r;
|
||||||
|
float b = (src_float_channels > 2) ? pix[2] : r;
|
||||||
|
float a = (src_float_channels > 3) ? pix[3] : 1.0f;
|
||||||
|
if (dst_channels == 1) {
|
||||||
|
float luma = 0.2126f * r + 0.7152f * g + 0.0722f * b;
|
||||||
|
dst_row_u16[x] = static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(luma) * 65535.0f));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dst_row_u16[x * dst_channels + 0] =
|
||||||
|
static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(r) * 65535.0f));
|
||||||
|
dst_row_u16[x * dst_channels + 1] =
|
||||||
|
static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(g) * 65535.0f));
|
||||||
|
dst_row_u16[x * dst_channels + 2] =
|
||||||
|
static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(b) * 65535.0f));
|
||||||
|
if (dst_channels == 4) {
|
||||||
|
dst_row_u16[x * dst_channels + 3] =
|
||||||
|
static_cast<uint16_t>(
|
||||||
|
std::lround(clamp01(a) * 65535.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int x = 0; x < src->width; ++x) {
|
||||||
|
const float *pix =
|
||||||
|
src_row + x * src_float_channels;
|
||||||
|
float r = pix[0];
|
||||||
|
float g = (src_float_channels > 1) ? pix[1] : r;
|
||||||
|
float b = (src_float_channels > 2) ? pix[2] : r;
|
||||||
|
float a = (src_float_channels > 3) ? pix[3] : 1.0f;
|
||||||
|
if (dst_channels == 1) {
|
||||||
|
float luma = 0.2126f * r + 0.7152f * g + 0.0722f * b;
|
||||||
|
dst_row[x] = static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(luma) * 255.0f));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dst_row[x * dst_channels + 0] =
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(r) * 255.0f));
|
||||||
|
dst_row[x * dst_channels + 1] =
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(g) * 255.0f));
|
||||||
|
dst_row[x * dst_channels + 2] =
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(b) * 255.0f));
|
||||||
|
if (dst_channels == 4) {
|
||||||
|
dst_row[x * dst_channels + 3] =
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
std::lround(clamp01(a) * 255.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SwsContext *sws_ctx = sws_getContext(
|
SwsContext *sws_ctx = sws_getContext(
|
||||||
src->width, src->height, static_cast<AVPixelFormat>(src->format),
|
src->width, src->height, static_cast<AVPixelFormat>(src->format),
|
||||||
dst->width, dst->height, dst_fmt, SWS_POINT,
|
dst->width, dst->height, dst_fmt, SWS_POINT,
|
||||||
@@ -407,6 +662,42 @@ static int LinesizeToPixels(const olive::VideoParams ¶ms, int linesize_bytes
|
|||||||
return linesize_bytes / bytes_per_pixel;
|
return linesize_bytes / bytes_per_pixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static olive::TexturePtr ConvertTextureForParams(olive::TexturePtr src,
|
||||||
|
const olive::VideoParams &dst_params)
|
||||||
|
{
|
||||||
|
if (!src) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const olive::VideoParams &src_params = src->params();
|
||||||
|
if (src_params.format() == dst_params.format() &&
|
||||||
|
src_params.channel_count() == dst_params.channel_count() &&
|
||||||
|
src_params.width() == dst_params.width() &&
|
||||||
|
src_params.height() == dst_params.height()) {
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
olive::AVFramePtr frame = src->frame();
|
||||||
|
if (!frame || !frame->data[0]) {
|
||||||
|
frame = ReadbackTextureToFrame(src, src_params);
|
||||||
|
}
|
||||||
|
if (!frame || !frame->data[0]) {
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
olive::AVFramePtr converted = ConvertFrameIfNeeded(frame, dst_params);
|
||||||
|
if (!converted || !converted->data[0]) {
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dst = std::make_shared<olive::Texture>(dst_params);
|
||||||
|
int linesize_pixels = LinesizeToPixels(dst_params, converted->linesize[0]);
|
||||||
|
if (linesize_pixels <= 0) {
|
||||||
|
linesize_pixels = dst_params.effective_width();
|
||||||
|
}
|
||||||
|
dst->Upload(converted->data[0], linesize_pixels);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
static QString PluginIdForInstance(const OFX::Host::ImageEffect::Instance *instance)
|
static QString PluginIdForInstance(const OFX::Host::ImageEffect::Instance *instance)
|
||||||
{
|
{
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
@@ -432,15 +723,15 @@ static void LogOfxFailure(const char *action, OfxStatus stat,
|
|||||||
<< "(" << stat << ")";
|
<< "(" << stat << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MarkRenderFailure(olive::Texture *destination)
|
static void MarkRenderFailure(olive::TexturePtr destination)
|
||||||
{
|
{
|
||||||
if (destination && destination->renderer()) {
|
if (destination && destination->renderer()) {
|
||||||
destination->renderer()->ClearDestination(destination, 1.0, 0.0, 1.0, 1.0);
|
destination->renderer()->ClearDestination(destination.get(), 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::TexturePtr destination,
|
||||||
olive::VideoParams destination_params,
|
olive::VideoParams destination_params,
|
||||||
bool clear_destination, bool interactive)
|
bool clear_destination, bool interactive)
|
||||||
{
|
{
|
||||||
@@ -448,10 +739,18 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
if (!instance) {
|
if (!instance) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
bool supports_opengl = false;
|
||||||
|
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
||||||
|
const std::string &gl_supported =
|
||||||
|
instance->getDescriptor().getProps().getStringProperty(
|
||||||
|
kOfxImageEffectPropOpenGLRenderSupported);
|
||||||
|
supports_opengl = (gl_supported == "true" || gl_supported == "1");
|
||||||
|
#endif
|
||||||
auto *olive_instance =
|
auto *olive_instance =
|
||||||
dynamic_cast<olive::plugin::OlivePluginInstance *>(instance);
|
dynamic_cast<olive::plugin::OlivePluginInstance *>(instance);
|
||||||
const bool use_opengl =
|
const bool use_opengl =
|
||||||
destination && destination->renderer() && destination->id().isValid();
|
supports_opengl && 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);
|
olive_instance->setVideoParam(destination_params);
|
||||||
@@ -501,7 +800,7 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 = job.time_seconds();
|
||||||
|
|
||||||
const NodeValueRow &values = job.GetValues();
|
const NodeValueRow &values = job.GetValues();
|
||||||
const auto &clips = instance->getDescriptor().getClips();
|
const auto &clips = instance->getDescriptor().getClips();
|
||||||
@@ -523,7 +822,6 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
}
|
}
|
||||||
if (input_tex) {
|
if (input_tex) {
|
||||||
input_textures[entry.first] = input_tex;
|
input_textures[entry.first] = input_tex;
|
||||||
input_clip->setInputTexture(input_tex, frame);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,6 +836,8 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
olive::VideoParams output_params = destination_params;
|
olive::VideoParams output_params = destination_params;
|
||||||
if (ApplyClipPreferencesToParams(*clip, &output_params)) {
|
if (ApplyClipPreferencesToParams(*clip, &output_params)) {
|
||||||
clip->setParams(output_params);
|
clip->setParams(output_params);
|
||||||
@@ -551,15 +851,27 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
}
|
}
|
||||||
olive::VideoParams input_params = entry.second->params();
|
olive::VideoParams input_params = entry.second->params();
|
||||||
if (ApplyClipPreferencesToParams(*input_clip, &input_params)) {
|
if (ApplyClipPreferencesToParams(*input_clip, &input_params)) {
|
||||||
|
/*
|
||||||
|
input_params.set_width(entry.second->params().width());
|
||||||
|
input_params.set_height(entry.second->params().height());
|
||||||
|
input_params.set_depth(entry.second->params().depth());
|
||||||
|
input_params.set_pixel_aspect_ratio(
|
||||||
|
entry.second->params().pixel_aspect_ratio());
|
||||||
|
input_params.set_interlacing(entry.second->params().interlacing());
|
||||||
|
input_params.set_premultiplied_alpha(
|
||||||
|
entry.second->params().premultiplied_alpha());
|
||||||
|
input_params.set_divider(entry.second->params().divider());*/
|
||||||
input_clip->setParams(input_params);
|
input_clip->setParams(input_params);
|
||||||
}
|
}
|
||||||
input_clip->setInputTexture(entry.second, frame);
|
olive::TexturePtr converted =
|
||||||
|
ConvertTextureForParams(entry.second, input_params);
|
||||||
|
input_clip->setInputTexture(converted, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
clip->setRegionOfDefinition(regionOfDefinition, frame);
|
clip->setRegionOfDefinition(regionOfDefinition, frame);
|
||||||
clip->setOutputTexture(destination, frame);
|
clip->setOutputTexture(destination, frame);
|
||||||
|
|
||||||
stat = instance->beginRenderAction(0, numFramesToRender,
|
stat = instance->beginRenderAction(frame, numFramesToRender,
|
||||||
1.0, false, renderScale, true,
|
1.0, false, renderScale, true,
|
||||||
interactive);
|
interactive);
|
||||||
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||||
@@ -589,14 +901,24 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!output_params.is_valid()) {
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "OFX render skipped due to invalid output params for plugin="
|
||||||
|
<< PluginIdForInstance(instance);
|
||||||
|
MarkRenderFailure(destination);
|
||||||
|
instance->endRenderAction(frame, numFramesToRender, 1.0, interactive,
|
||||||
|
renderScale, true, interactive);
|
||||||
|
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(frame, render_field, renderWindow, renderScale,
|
||||||
true, interactive, interactive);
|
true, interactive, interactive);
|
||||||
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
if (stat != kOfxStatOK && stat != kOfxStatReplyDefault) {
|
||||||
LogOfxFailure("render", stat, instance);
|
LogOfxFailure("render", stat, instance);
|
||||||
MarkRenderFailure(destination);
|
MarkRenderFailure(destination);
|
||||||
instance->endRenderAction(0, numFramesToRender, 1.0, interactive,
|
instance->endRenderAction(frame, numFramesToRender, 1.0, interactive,
|
||||||
renderScale, true, interactive);
|
renderScale, true, interactive);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -636,19 +958,27 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
qWarning().noquote()
|
qWarning().noquote()
|
||||||
<< "OFX output image conversion failed for plugin="
|
<< "OFX output image conversion failed for plugin="
|
||||||
<< PluginIdForInstance(instance);
|
<< PluginIdForInstance(instance);
|
||||||
instance->endRenderAction(0, numFramesToRender, 1.0, interactive,
|
instance->endRenderAction(frame, 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);
|
||||||
|
const AVPixelFormat expected_fmt =
|
||||||
|
GetDestinationAVPixelFormat(destination_params);
|
||||||
destination->handleFrame(converted);
|
destination->handleFrame(converted);
|
||||||
if (destination->renderer() && converted && converted->data[0]) {
|
if (destination->renderer() && converted && converted->data[0] &&
|
||||||
|
(expected_fmt == AV_PIX_FMT_NONE ||
|
||||||
|
converted->format == expected_fmt)) {
|
||||||
int linesize_pixels =
|
int linesize_pixels =
|
||||||
LinesizeToPixels(destination_params, converted->linesize[0]);
|
LinesizeToPixels(destination_params, converted->linesize[0]);
|
||||||
if (linesize_pixels <= 0) {
|
if (linesize_pixels <= 0) {
|
||||||
linesize_pixels = destination_params.effective_width();
|
linesize_pixels = destination_params.effective_width();
|
||||||
}
|
}
|
||||||
destination->Upload(converted->data[0], linesize_pixels);
|
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);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AVFramePtr frame_ptr =
|
AVFramePtr frame_ptr =
|
||||||
@@ -669,7 +999,7 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void olive::plugin::PluginRenderer::AttachOutputTexture(olive::Texture *texture)
|
void olive::plugin::PluginRenderer::AttachOutputTexture(olive::TexturePtr texture)
|
||||||
{
|
{
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -37,15 +37,18 @@
|
|||||||
namespace olive
|
namespace olive
|
||||||
{
|
{
|
||||||
namespace plugin{
|
namespace plugin{
|
||||||
|
namespace detail {
|
||||||
|
int BytesToPixels(int byte_linesize, const olive::VideoParams ¶ms);
|
||||||
|
}
|
||||||
class PluginRenderer : public olive::OpenGLRenderer{
|
class PluginRenderer : public olive::OpenGLRenderer{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
PluginRenderer(QObject *parent=nullptr):OpenGLRenderer(parent){};
|
PluginRenderer(QObject *parent=nullptr):OpenGLRenderer(parent){};
|
||||||
virtual ~PluginRenderer() override{};
|
virtual ~PluginRenderer() override{};
|
||||||
void AttachOutputTexture(olive::Texture *texture);
|
void AttachOutputTexture(olive::TexturePtr texture);
|
||||||
void DetachOutputTexture();
|
void DetachOutputTexture();
|
||||||
void RenderPlugin(TexturePtr src, olive::plugin::PluginJob& job,
|
void RenderPlugin(TexturePtr src, olive::plugin::PluginJob& job,
|
||||||
olive::Texture *destination,
|
olive::TexturePtr destination,
|
||||||
olive::VideoParams destination_params,
|
olive::VideoParams destination_params,
|
||||||
bool clear_destination, bool interactive);
|
bool clear_destination, bool interactive);
|
||||||
|
|
||||||
|
|||||||
@@ -638,7 +638,7 @@ TexturePtr RenderProcessor::ProcessPluginJob(TexturePtr texture,
|
|||||||
plugin_renderer_->RenderPlugin(
|
plugin_renderer_->RenderPlugin(
|
||||||
texture,
|
texture,
|
||||||
*plugin_job,
|
*plugin_job,
|
||||||
destination.get(),
|
destination,
|
||||||
destination->params(),
|
destination->params(),
|
||||||
true,
|
true,
|
||||||
false);
|
false);
|
||||||
|
|||||||
@@ -59,16 +59,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void SetChannelLayout(AVChannelLayout &ch)
|
void SetChannelLayout(const AVChannelLayout &ch)
|
||||||
{
|
|
||||||
for (int i = 0; i < this->count(); i++) {
|
|
||||||
if (this->itemData(i).toULongLong() == ch.u.mask) {
|
|
||||||
this->setCurrentIndex(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void SetChannelLayout(AVChannelLayout &&ch)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < this->count(); i++) {
|
for (int i = 0; i < this->count(); i++) {
|
||||||
if (this->itemData(i).toULongLong() == ch.u.mask) {
|
if (this->itemData(i).toULongLong() == ch.u.mask) {
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ 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_support_param_test.cpp
|
||||||
|
opengl_readback_guard_test.cpp
|
||||||
plugin_render_pipeline_test.cpp
|
plugin_render_pipeline_test.cpp
|
||||||
|
plugin_renderer_readback_test.cpp
|
||||||
plugin_ofx_integration_test.cpp
|
plugin_ofx_integration_test.cpp
|
||||||
codec_frame_test.cpp
|
codec_frame_test.cpp
|
||||||
codec_exportcodec_test.cpp
|
codec_exportcodec_test.cpp
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <QOpenGLContext>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include "render/opengl/openglrenderer.h"
|
||||||
|
|
||||||
|
TEST(OpenGLRenderer, DownloadFromTextureWithoutCurrentContext)
|
||||||
|
{
|
||||||
|
QOpenGLContext context;
|
||||||
|
ASSERT_TRUE(context.create());
|
||||||
|
ASSERT_EQ(QOpenGLContext::currentContext(), nullptr);
|
||||||
|
|
||||||
|
olive::OpenGLRenderer renderer;
|
||||||
|
renderer.Init(&context);
|
||||||
|
|
||||||
|
olive::VideoParams params(4, 4, olive::core::PixelFormat::U8, 4,
|
||||||
|
olive::core::rational(1, 1),
|
||||||
|
olive::VideoParams::kInterlaceNone, 1);
|
||||||
|
|
||||||
|
unsigned char buffer[4 * 4 * 4] = {};
|
||||||
|
renderer.DownloadFromTexture(QVariant::fromValue<GLuint>(0), params,
|
||||||
|
buffer, 4 * 4);
|
||||||
|
|
||||||
|
EXPECT_EQ(QOpenGLContext::currentContext(), nullptr);
|
||||||
|
}
|
||||||
@@ -114,7 +114,7 @@ TEST(PluginIntegration, ChromaKeyerCreateAndRender)
|
|||||||
olive::TexturePtr output = std::make_shared<olive::Texture>(params);
|
olive::TexturePtr output = std::make_shared<olive::Texture>(params);
|
||||||
|
|
||||||
olive::plugin::PluginRenderer renderer;
|
olive::plugin::PluginRenderer renderer;
|
||||||
renderer.RenderPlugin(input, job, output.get(), params, true, false);
|
renderer.RenderPlugin(input, job, output, params, true, false);
|
||||||
|
|
||||||
EXPECT_TRUE(output->frame());
|
EXPECT_TRUE(output->frame());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "render/plugin/pluginrenderer.h"
|
||||||
|
|
||||||
|
TEST(PluginRendererReadback, BytesToPixels)
|
||||||
|
{
|
||||||
|
olive::VideoParams params(16, 16, olive::core::PixelFormat::U8, 4,
|
||||||
|
olive::core::rational(1, 1),
|
||||||
|
olive::VideoParams::kInterlaceNone, 1);
|
||||||
|
|
||||||
|
const int bytes_per_pixel =
|
||||||
|
olive::VideoParams::GetBytesPerPixel(params.format(),
|
||||||
|
params.channel_count());
|
||||||
|
ASSERT_EQ(bytes_per_pixel, 4);
|
||||||
|
|
||||||
|
EXPECT_EQ(olive::plugin::detail::BytesToPixels(64, params), 16);
|
||||||
|
EXPECT_EQ(olive::plugin::detail::BytesToPixels(0, params), 0);
|
||||||
|
EXPECT_EQ(olive::plugin::detail::BytesToPixels(-1, params), 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "ofxParam.h"
|
||||||
|
#include "ofxhParam.h"
|
||||||
|
#include "pluginSupport/paraminstance.h"
|
||||||
|
|
||||||
|
TEST(PluginSupportParam, IntegerInstanceNullNodeRoundTrip)
|
||||||
|
{
|
||||||
|
OFX::Host::Param::Descriptor descriptor(kOfxParamTypeInteger,
|
||||||
|
"TestInteger");
|
||||||
|
olive::plugin::IntegerInstance instance(nullptr, descriptor);
|
||||||
|
|
||||||
|
int value = -1;
|
||||||
|
EXPECT_EQ(instance.get(value), kOfxStatOK);
|
||||||
|
EXPECT_EQ(value, 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(instance.set(7), kOfxStatOK);
|
||||||
|
EXPECT_EQ(instance.get(value), kOfxStatOK);
|
||||||
|
EXPECT_EQ(value, 7);
|
||||||
|
|
||||||
|
int time_value = -1;
|
||||||
|
EXPECT_EQ(instance.get(1.0, time_value), kOfxStatOK);
|
||||||
|
EXPECT_EQ(time_value, 7);
|
||||||
|
}
|
||||||
@@ -78,13 +78,13 @@ namespace OFX {
|
|||||||
virtual bool pluginSupported(ImageEffectPlugin *plugin, std::string &reason) const;
|
virtual bool pluginSupported(ImageEffectPlugin *plugin, std::string &reason) const;
|
||||||
|
|
||||||
/// Override this to create a descriptor, this makes the 'root' descriptor
|
/// Override this to create a descriptor, this makes the 'root' descriptor
|
||||||
virtual Descriptor *makeDescriptor(ImageEffectPlugin* plugin) = 0;
|
virtual std::shared_ptr<Descriptor> makeDescriptor(ImageEffectPlugin* plugin) = 0;
|
||||||
|
|
||||||
/// used to construct a context description, rootContext is the main context
|
/// used to construct a context description, rootContext is the main context
|
||||||
virtual Descriptor *makeDescriptor(const Descriptor &rootContext, ImageEffectPlugin *plug) = 0;
|
virtual std::shared_ptr<Descriptor> makeDescriptor(const Descriptor &rootContext, ImageEffectPlugin *plug) = 0;
|
||||||
|
|
||||||
/// used to construct populate the cache
|
/// used to construct populate the cache
|
||||||
virtual Descriptor *makeDescriptor(const std::string &bundlePath, ImageEffectPlugin *plug) = 0;
|
virtual std::shared_ptr<Descriptor> makeDescriptor(const std::string &bundlePath, ImageEffectPlugin *plug) = 0;
|
||||||
|
|
||||||
/// Override this to initialise an image effect descriptor after it has been
|
/// Override this to initialise an image effect descriptor after it has been
|
||||||
/// created.
|
/// created.
|
||||||
|
|||||||
@@ -34,10 +34,10 @@
|
|||||||
|
|
||||||
// this comes off Descriptor's property set after a describe
|
// this comes off Descriptor's property set after a describe
|
||||||
// context independent
|
// context independent
|
||||||
Descriptor *_baseDescriptor; /// NEEDS TO BE MADE WITH A FACTORY FUNCTION ON THE HOST!!!!!!
|
std::shared_ptr<Descriptor> _baseDescriptor; /// NEEDS TO BE MADE WITH A FACTORY FUNCTION ON THE HOST!!!!!!
|
||||||
|
|
||||||
/// map to store contexts in
|
/// map to store contexts in
|
||||||
std::map<std::string, std::unique_ptr<Descriptor>> _contexts;
|
std::map<std::string, std::shared_ptr<Descriptor>> _contexts;
|
||||||
|
|
||||||
mutable std::set<std::string> _knownContexts;
|
mutable std::set<std::string> _knownContexts;
|
||||||
mutable bool _madeKnownContexts;
|
mutable bool _madeKnownContexts;
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
Descriptor *getContext(const std::string &context);
|
Descriptor *getContext(const std::string &context);
|
||||||
|
|
||||||
void addContext(const std::string &context);
|
void addContext(const std::string &context);
|
||||||
void addContext(const std::string &context, std::unique_ptr<Descriptor> ied);
|
void addContext(const std::string &context, std::shared_ptr<Descriptor> ied);
|
||||||
|
|
||||||
virtual void saveXML(std::ostream &os);
|
virtual void saveXML(std::ostream &os);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -83,7 +84,6 @@ namespace OFX {
|
|||||||
} CatchAllSetStatus(stat, gImageEffectHost, op, kOfxActionUnload);
|
} CatchAllSetStatus(stat, gImageEffectHost, op, kOfxActionUnload);
|
||||||
(void)stat;
|
(void)stat;
|
||||||
}
|
}
|
||||||
delete _baseDescriptor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
APICache::PluginAPICacheI &ImageEffectPlugin::getApiHandler()
|
APICache::PluginAPICacheI &ImageEffectPlugin::getApiHandler()
|
||||||
@@ -102,9 +102,9 @@ namespace OFX {
|
|||||||
return *_baseDescriptor;
|
return *_baseDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageEffectPlugin::addContext(const std::string &context, std::unique_ptr<Descriptor> ied)
|
void ImageEffectPlugin::addContext(const std::string &context, std::shared_ptr<Descriptor> ied)
|
||||||
{
|
{
|
||||||
_contexts[context] = std::move(ied);
|
_contexts[context] = ied;
|
||||||
_knownContexts.insert(context);
|
_knownContexts.insert(context);
|
||||||
_madeKnownContexts = true;
|
_madeKnownContexts = true;
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,7 @@ namespace OFX {
|
|||||||
|
|
||||||
Descriptor *ImageEffectPlugin::getContext(const std::string &context)
|
Descriptor *ImageEffectPlugin::getContext(const std::string &context)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::unique_ptr<Descriptor>>::iterator it = _contexts.find(context);
|
std::map<std::string, std::shared_ptr<Descriptor>>::iterator it = _contexts.find(context);
|
||||||
|
|
||||||
if (it != _contexts.end()) {
|
if (it != _contexts.end()) {
|
||||||
//printf("found context description.\n");
|
//printf("found context description.\n");
|
||||||
@@ -214,7 +214,7 @@ namespace OFX {
|
|||||||
if (!ph) {
|
if (!ph) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::unique_ptr<ImageEffect::Descriptor> newContext( gImageEffectHost->makeDescriptor(getDescriptor(), this));
|
std::shared_ptr<ImageEffect::Descriptor> newContext( gImageEffectHost->makeDescriptor(getDescriptor(), this));
|
||||||
|
|
||||||
OfxStatus stat;
|
OfxStatus stat;
|
||||||
try {
|
try {
|
||||||
@@ -463,9 +463,9 @@ namespace OFX {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (el == "context") {
|
if (el == "context") {
|
||||||
std::unique_ptr<Descriptor> newContext(gImageEffectHost->makeDescriptor(_currentPlugin->getBinary()->getBundlePath(), _currentPlugin));
|
std::shared_ptr<Descriptor> newContext = gImageEffectHost->makeDescriptor(_currentPlugin->getBinary()->getBundlePath(), _currentPlugin);
|
||||||
_currentContext = newContext.get();
|
_currentContext = newContext.get();
|
||||||
_currentPlugin->addContext(map["name"], std::move(newContext));
|
_currentPlugin->addContext(map["name"], newContext);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user