Automated with clang-tidy readability-identifier-naming (config added to .clang-tidy) plus scripted passes, per the updated rules now documented in CONTRIBUTING.md: - types (class/struct/enum/alias/template params): PascalCase - functions, variables, members: snake_case (incl. rational -> Rational) - private/protected members: trailing underscore; static member variables likewise (instance_, available_themes_) - constants and enum values: snake_case (kLinear -> k_linear, F32P -> f32p); ALL_CAPS reserved for macros - macros: OAK_ prefix (OLIVE_ADD_TEST/OLIVE_ASSERT/OLIVE_CONFIG -> OAK_ADD_TEST/OAK_ASSERT/OAK_CONFIG, GL_PREAMBLE -> OAK_GL_PREAMBLE, include guards -> OAK_*) - file names: all lowercase (Current/Plugin/OliveHost/OliveClip/ OlivePluginInstance -> current/plugin/olivehost/oliveclip/ oliveplugininstance) - getters share the member name sans underscore, setters set_foo() - Qt and third-party (OpenFX) virtual overrides and framework callbacks keep their original names (exempt in .clang-tidy) Manual follow-ups required where automation could not reach: - string-based QMetaObject/SIGNAL/SLOT references updated to renamed methods (AddTask, CreatedFile, DeleteSpecificFile, moveSelectionUp, ...) - macro bodies referencing renamed methods (OLIVE_CONFIG, NODE_DEFAULT_DESTRUCTOR, MANAGEDDISPLAYWIDGET_*) - self-shadowing locals renamed where signals/methods became same-named (size_changed, worker_count, selected_items, import param, filters) - third_party OFX member/namespace usages restored (OFX::Host::*, _created, _clipPrefsDirty, createInstance, clearPersistentMessage) - STL protocol aliases restored (const_iterator) with .clang-tidy ignore rules; qHash overloads restored Full build and test suite pass: ctest 4/4, ~1960 gtest cases green.
124 lines
3.5 KiB
C++
124 lines
3.5 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "common/ffmpegutils.h"
|
|
#include "node/value.h"
|
|
#include "pluginSupport/olivehost.h"
|
|
#include "pluginSupport/oliveplugininstance.h"
|
|
#include "render/job/pluginjob.h"
|
|
#include "render/plugin/pluginrenderer.h"
|
|
#include "render/texture.h"
|
|
#include "render/videoparams.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
olive::TexturePtr create_solid_texture(const olive::VideoParams ¶ms)
|
|
{
|
|
olive::AVFramePtr frame = olive::create_av_frame_ptr();
|
|
frame->set_format(olive::FFmpegUtils::get_f_fmpeg_pixel_format(
|
|
params.format(), params.channel_count()));
|
|
frame->set_width(params.width());
|
|
frame->set_height(params.height());
|
|
if (frame->format() == fb_pix_fmt_none) {
|
|
return nullptr;
|
|
}
|
|
if (frame->get_buffer(0) < 0) {
|
|
return nullptr;
|
|
}
|
|
if (frame->make_writable() < 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
const int linesize = frame->linesize(0);
|
|
for (int y = 0; y < frame->height(); ++y) {
|
|
std::memset(frame->data(0) + y * linesize, 0x7f, linesize);
|
|
}
|
|
|
|
olive::TexturePtr texture = std::make_shared<olive::Texture>(params);
|
|
texture->handle_frame(frame);
|
|
return texture;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(PluginIntegration, ChromaKeyerCreateAndRender)
|
|
{
|
|
const char *itest = std::getenv("OAK_OFX_ITEST");
|
|
if (!itest || std::string(itest) != "1") {
|
|
GTEST_SKIP() << "OAK_OFX_ITEST not enabled";
|
|
}
|
|
|
|
const char *path = std::getenv("OAK_OFX_PLUGIN_PATH");
|
|
if (!path || std::string(path).empty()) {
|
|
GTEST_SKIP() << "OAK_OFX_PLUGIN_PATH not set";
|
|
}
|
|
|
|
std::string plugin_id = "net.sf.openfx.ChromaKeyerPlugin";
|
|
if (const char *env_id = std::getenv("OAK_OFX_PLUGIN_ID")) {
|
|
if (*env_id) {
|
|
plugin_id = env_id;
|
|
}
|
|
}
|
|
|
|
QString raw = QString::fromUtf8(path);
|
|
const QChar separator = QDir::listSeparator();
|
|
const QStringList paths = raw.split(separator, Qt::SkipEmptyParts);
|
|
for (const QString &p : paths) {
|
|
olive::plugin::load_plugins(p);
|
|
}
|
|
|
|
auto *cache = OFX::Host::PluginCache::getPluginCache();
|
|
OFX::Host::Plugin *found = nullptr;
|
|
for (auto *plug : cache->getPlugins()) {
|
|
if (plug && plug->getIdentifier() == plugin_id) {
|
|
found = plug;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
GTEST_SKIP() << "Plugin not found: " << plugin_id;
|
|
}
|
|
|
|
auto *image_effect =
|
|
dynamic_cast<OFX::Host::ImageEffect::ImageEffectPlugin *>(found);
|
|
ASSERT_TRUE(image_effect);
|
|
|
|
const auto &contexts = image_effect->getContexts();
|
|
std::string context = kOfxImageEffectContextFilter;
|
|
if (!contexts.empty() &&
|
|
contexts.find(kOfxImageEffectContextFilter) == contexts.end()) {
|
|
context = *contexts.begin();
|
|
}
|
|
|
|
OFX::Host::ImageEffect::Instance *instance =
|
|
image_effect->createInstance(context, nullptr);
|
|
ASSERT_TRUE(instance);
|
|
|
|
auto *olive_instance =
|
|
dynamic_cast<olive::plugin::OlivePluginInstance *>(instance);
|
|
ASSERT_TRUE(olive_instance);
|
|
|
|
// Use U16 format as the ChromaKeyer plugin expects 16-bit input
|
|
olive::VideoParams params(320, 240, olive::core::PixelFormat::u16, 4);
|
|
olive_instance->setVideoParam(params);
|
|
|
|
olive::TexturePtr input = create_solid_texture(params);
|
|
ASSERT_TRUE(input);
|
|
|
|
olive::NodeValueRow row;
|
|
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
|
|
olive::NodeValue(olive::NodeValue::k_texture, input));
|
|
row.insert(QStringLiteral("Bg"),
|
|
olive::NodeValue(olive::NodeValue::k_texture, input));
|
|
|
|
olive::plugin::PluginJob job(instance, nullptr, row);
|
|
olive::TexturePtr output = std::make_shared<olive::Texture>(params);
|
|
|
|
olive::plugin::PluginRenderer renderer(nullptr);
|
|
renderer.render_plugin(input, job, output, params, true, false);
|
|
|
|
EXPECT_TRUE(output->frame());
|
|
}
|