build/ci: green builds and tests on all three platforms
Compiler hygiene (all platforms): - Silence warnings across the tree: missing override, -Wreorder ctor init, -Wshadow, -Wsign-compare, missing switch cases, unused functions/captures, Qt 6.11 deprecations (QMouseEvent/QDropEvent accessors, qAsConst, Q_FOREACH over non-shared containers, AA_UseHighDpiPixmaps) and the .bak/ backup tree removal. - Fix regressions from the cleanup: missing clip decls in capi/timeline.cpp, plugin.cpp rename fallout, panel setFocus ambiguity, QGraphicsItem::pos vs event->position(), duplicate k_push_button case, boolean test variable. Windows: - Qt portability: CommandLineParser is_set/add_option, QTimeZone systemTimeZone (QTimeZone::LocalTime is 6.11-only), k_progress_* enum. - Linking: stop adding oakengine to OLIVE_LIBRARIES (import lib plus oakengine-obj caused multiple definitions); add OAKENGINE_STATIC so internal consumers no longer reference __imp_* stubs. - oakengine.ver: export olive::Renderer typeinfo so liboakgl.so can be dlopened (Linux), DynamicRenderer no longer dlcloses backend libraries (crash in RenderManager's dtor calling into unmapped memory). - OTIO runtime: copy DLLs next to every binary on Windows instead of relying on PATH (0xc0000135 in gtest discovery). - Headless GL: the runner only has GDI OpenGL 1.1, killing every render worker. Deploy Mesa llvmpipe as opengl32sw.dll (Qt's software-GL channel) with QT_OPENGL=software, and let QT_OPENGL override the AA_UseDesktopOpenGL default. ExportTask fails fast after 8 consecutive undelivered frames instead of segfaulting or grinding forever; FFmpegEncoder::write_frame tolerates null frames. - Tests: GetTempPathA+PID temp dirs, GetLongPathNameA for 8.3 names, forward-slash normalization when comparing project filenames. Linux: - Install libshaderc-dev so oakvulkan compiles GLSL (Vulkan tests). - Accept UNORM floor-or-round (63/64) in the blit ping-pong test. - Skip MainWindow construction test on the offscreen QPA (cannot paint QOpenGLWidget). Also: oak_cli_transcode gets a 300s ctest timeout, worker logs GL context version and LoadGraph/render_frame stages, and docs/plans/eliminate-event-bridge-issues.md (English translation).
This commit is contained in:
@@ -114,6 +114,9 @@ target_include_directories(oakengine
|
||||
target_link_libraries(oakengine PUBLIC ${OLIVE_LIBRARIES} OfxHost)
|
||||
# OAKENGINE_BUILD marks the library side of the C ABI export macros (dllexport)
|
||||
target_compile_definitions(oakengine-obj PRIVATE ${OLIVE_DEFINITIONS} OAKENGINE_BUILD)
|
||||
# Consumers that link the object library directly (app, tests, Windows oakgl)
|
||||
# must see plain C declarations, not __declspec(dllimport) ones.
|
||||
target_compile_definitions(oakengine-obj INTERFACE OAKENGINE_STATIC)
|
||||
target_compile_options(oakengine-obj PRIVATE ${OLIVE_COMPILE_OPTIONS})
|
||||
|
||||
# Version script: only oakengine_* + render-backend plugin ABI are exported;
|
||||
|
||||
@@ -324,6 +324,14 @@ bool FFmpegEncoder::open()
|
||||
|
||||
bool FFmpegEncoder::write_frame(FramePtr frame, Rational time)
|
||||
{
|
||||
// The render worker pool finishes tickets without a result when no
|
||||
// worker is available (or the worker crashed); a null frame must fail
|
||||
// the encode cleanly instead of crashing the export task.
|
||||
if (!frame) {
|
||||
qWarning() << "FFmpegEncoder::write_frame called with null frame";
|
||||
return false;
|
||||
}
|
||||
|
||||
// We may need to convert this frame to a frame that the bridge will understand
|
||||
if (frame->format() != video_conversion_fmt_) {
|
||||
frame = frame->convert(video_conversion_fmt_);
|
||||
|
||||
@@ -275,7 +275,7 @@ void Html::write_char_format(QString *style, const QTextCharFormat &fmt)
|
||||
}
|
||||
|
||||
if (fmt.foreground().style() != Qt::NoBrush) {
|
||||
const QColor &color = fmt.foreground().color();
|
||||
const QColor color = fmt.foreground().color();
|
||||
QString cs;
|
||||
|
||||
if (color.alpha() == 255) {
|
||||
|
||||
@@ -225,7 +225,7 @@ public:
|
||||
~Arena()
|
||||
{
|
||||
std::list<Element *> copy = lent_elements_;
|
||||
foreach (Element *e, copy) {
|
||||
for (Element *e : copy) {
|
||||
e->release();
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ public:
|
||||
QMutexLocker locker(&lock_);
|
||||
|
||||
// Attempt to get an element from an arena
|
||||
foreach (Arena *a, arenas_) {
|
||||
for (Arena *a : arenas_) {
|
||||
ElementPtr e = a->Get();
|
||||
|
||||
if (e) {
|
||||
|
||||
@@ -49,6 +49,10 @@ PixelFormat OIIOUtils::get_format_from_oiio_basetype(OIIO::TypeDesc::BASETYPE ty
|
||||
switch (type) {
|
||||
case OIIO::TypeDesc::UNKNOWN:
|
||||
case OIIO::TypeDesc::NONE:
|
||||
#if OIIO_VERSION >= 20500
|
||||
case OIIO::TypeDesc::USTRINGHASH:
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
|
||||
case OIIO::TypeDesc::INT8:
|
||||
|
||||
@@ -544,10 +544,11 @@ void EngineCore::save_autorecovery()
|
||||
{
|
||||
QFile realname_file(project_autorecovery_dir.filePath(
|
||||
QStringLiteral("realname.txt")));
|
||||
realname_file.open(QFile::WriteOnly);
|
||||
realname_file.write(
|
||||
open_project_->pretty_filename().toUtf8());
|
||||
realname_file.close();
|
||||
if (realname_file.open(QFile::WriteOnly)) {
|
||||
realname_file.write(
|
||||
open_project_->pretty_filename().toUtf8());
|
||||
realname_file.close();
|
||||
}
|
||||
}
|
||||
|
||||
int64_t max_recoveries_per_file =
|
||||
|
||||
@@ -30,7 +30,11 @@
|
||||
* is still built with default symbol visibility, so the legacy C++ symbols
|
||||
* remain exported alongside the C ABI.
|
||||
*/
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#if defined(OAKENGINE_STATIC)
|
||||
/* Internal consumers link the engine object files directly (oakengine-obj)
|
||||
instead of the shared library; no dllimport/dllexport is wanted. */
|
||||
#define OAKENGINE_API
|
||||
#elif defined(_WIN32) || defined(__CYGWIN__)
|
||||
#ifdef OAKENGINE_BUILD
|
||||
#define OAKENGINE_API __declspec(dllexport)
|
||||
#else
|
||||
|
||||
@@ -2386,14 +2386,14 @@ TimeRange Node::transform_time_to(TimeRange time, Node *target,
|
||||
Node *from = this;
|
||||
Node *to = target;
|
||||
|
||||
if (dir == k_transform_towards_input) {
|
||||
if (dir == k_towards_input) {
|
||||
std::swap(from, to);
|
||||
}
|
||||
|
||||
std::list<NodeInput> path = find_path(from, to, path_index);
|
||||
|
||||
if (!path.empty()) {
|
||||
if (dir == k_transform_towards_input) {
|
||||
if (dir == k_towards_input) {
|
||||
for (auto it = path.crbegin(); it != path.crend(); it++) {
|
||||
const NodeInput &i = (*it);
|
||||
time = i.node()->input_time_adjustment(i.input(), i.element(),
|
||||
@@ -2614,7 +2614,7 @@ void Node::invalidate_from_keyframe_time_change()
|
||||
|
||||
// Invalidate entire area surrounding the keyframe (either where it currently is, or where it used to be before it
|
||||
// was resorted in the if block above)
|
||||
foreach (const TimeRange &r, invalidate_range) {
|
||||
for (const TimeRange &r : invalidate_range) {
|
||||
parameter_value_changed(key->key_track_ref().input(), r);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -929,8 +929,8 @@ public:
|
||||
static QString get_category_name(const CategoryID &c);
|
||||
|
||||
enum TransformTimeDirection {
|
||||
k_transform_towards_input,
|
||||
k_transform_towards_output
|
||||
k_towards_input,
|
||||
k_towards_output
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -232,8 +232,6 @@ QHash<QString, QVariant> build_default_values(
|
||||
ofx_type == kOfxParamTypePushButton) {
|
||||
continue;
|
||||
}
|
||||
const auto &props = param.second->getProperties();
|
||||
bool is_secret = props.getIntProperty(kOfxParamPropSecret) != 0;
|
||||
const QString input_id =
|
||||
QString::fromStdString(param.second->getName());
|
||||
if (input_id.isEmpty()) {
|
||||
@@ -263,10 +261,10 @@ clip_label_for_name(const std::string &name,
|
||||
}
|
||||
|
||||
if (desc) {
|
||||
const std::string &label =
|
||||
const std::string ¶m_label =
|
||||
desc->getProps().getStringProperty(kOfxPropLabel);
|
||||
if (!label.empty()) {
|
||||
return QString::fromStdString(label);
|
||||
if (!param_label.empty()) {
|
||||
return QString::fromStdString(param_label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,9 +430,9 @@ olive::plugin::PluginNode::PluginNode(OFX::Host::ImageEffect::Instance *plugin)
|
||||
const int value_count = props.getDimension(kOfxParamPropChoiceEnum);
|
||||
|
||||
for (int i = 0; i < label_count; ++i) {
|
||||
const std::string &label =
|
||||
const std::string &choice_label =
|
||||
props.getStringProperty(kOfxParamPropChoiceOption, i);
|
||||
option_labels.append(QString::fromStdString(label));
|
||||
option_labels.append(QString::fromStdString(choice_label));
|
||||
}
|
||||
|
||||
for (int i = 0; i < value_count; ++i) {
|
||||
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
*/
|
||||
virtual void process_samples(const NodeValueRow &values,
|
||||
const SampleBuffer &input, SampleBuffer &output,
|
||||
int index) const;
|
||||
int index) const override;
|
||||
|
||||
/**
|
||||
* @brief If Value() pushes a GenerateJob, override this function for the image to create
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
*
|
||||
* The destination buffer. It will already be allocated and ready for writing to.
|
||||
*/
|
||||
virtual void generate_frame(FramePtr frame, const GenerateJob &job) const;
|
||||
virtual void generate_frame(FramePtr frame, const GenerateJob &job) const override;
|
||||
|
||||
private:
|
||||
QString sub_category_;
|
||||
|
||||
@@ -377,8 +377,8 @@ void Footage::value(const NodeValueRow &value, const NodeGlobals &globals,
|
||||
this, QStringLiteral("length"));
|
||||
|
||||
// Push each stream as a footage job
|
||||
for (int i = 0; i < get_total_stream_count(); i++) {
|
||||
Track::Reference ref = get_reference_from_real_index(i);
|
||||
for (int si = 0; si < get_total_stream_count(); si++) {
|
||||
Track::Reference ref = get_reference_from_real_index(si);
|
||||
FootageJob job(globals.time(), decoder_, filename(), ref.type(),
|
||||
get_length(), globals.loop_mode());
|
||||
|
||||
@@ -427,9 +427,10 @@ void Footage::value(const NodeValueRow &value, const NodeGlobals &globals,
|
||||
ProxyManager::k_proxy_ready &&
|
||||
ProxyManager::proxy_filename_has_audio(proxy_path_)) {
|
||||
int audio_rank = 0;
|
||||
for (int i = 0; i < get_total_stream_count(); i++) {
|
||||
for (int sj = 0; sj < get_total_stream_count(); sj++) {
|
||||
const Track::Reference other =
|
||||
get_reference_from_real_index(i);
|
||||
get_reference_from_real_index(sj);
|
||||
|
||||
if (other.type() == Track::k_audio &&
|
||||
get_audio_params(other.index()).stream_index() <
|
||||
ap.stream_index()) {
|
||||
@@ -448,8 +449,8 @@ void Footage::value(const NodeValueRow &value, const NodeGlobals &globals,
|
||||
// Media is offline: push a generated warning frame for each video
|
||||
// stream so missing media is clearly visible in the timeline instead
|
||||
// of a transparent/black hole. generate_frame() draws the slat.
|
||||
for (int i = 0; i < get_total_stream_count(); i++) {
|
||||
Track::Reference ref = get_reference_from_real_index(i);
|
||||
for (int si = 0; si < get_total_stream_count(); si++) {
|
||||
Track::Reference ref = get_reference_from_real_index(si);
|
||||
if (ref.type() != Track::k_video) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ void SerializedLayoutInfo::to_xml(QXmlStreamWriter *writer) const
|
||||
|
||||
writer->writeStartElement(QStringLiteral("folders"));
|
||||
|
||||
foreach (Folder *folder, open_folders) {
|
||||
for (Folder *folder : open_folders) {
|
||||
writer->writeTextElement(
|
||||
QStringLiteral("folder"),
|
||||
QString::number(reinterpret_cast<quintptr>(folder)));
|
||||
@@ -38,7 +38,7 @@ void SerializedLayoutInfo::to_xml(QXmlStreamWriter *writer) const
|
||||
|
||||
writer->writeStartElement(QStringLiteral("timeline"));
|
||||
|
||||
foreach (Sequence *sequence, open_sequences) {
|
||||
for (Sequence *sequence : open_sequences) {
|
||||
writer->writeTextElement(
|
||||
QStringLiteral("sequence"),
|
||||
QString::number(reinterpret_cast<quintptr>(sequence)));
|
||||
@@ -48,7 +48,7 @@ void SerializedLayoutInfo::to_xml(QXmlStreamWriter *writer) const
|
||||
|
||||
writer->writeStartElement(QStringLiteral("viewers"));
|
||||
|
||||
foreach (ViewerOutput *viewer, open_viewers) {
|
||||
for (ViewerOutput *viewer : open_viewers) {
|
||||
writer->writeTextElement(
|
||||
QStringLiteral("viewer"),
|
||||
QString::number(reinterpret_cast<quintptr>(viewer)));
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "timeformat.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QTimeZone>
|
||||
|
||||
namespace olive
|
||||
{
|
||||
@@ -75,7 +76,8 @@ void TimeFormatNode::value(const NodeValueRow &value,
|
||||
qint64 ms_since_epoch = value[k_time_input].to_double() * 1000;
|
||||
bool time_is_local = value[k_local_time_input].to_bool();
|
||||
QDateTime dt = QDateTime::fromMSecsSinceEpoch(
|
||||
ms_since_epoch, time_is_local ? Qt::LocalTime : Qt::UTC);
|
||||
ms_since_epoch,
|
||||
time_is_local ? QTimeZone::systemTimeZone() : QTimeZone::utc());
|
||||
QString format = value[k_format_input].to_string();
|
||||
QString output = dt.toString(format);
|
||||
table->push(NodeValue(NodeValue::k_text, output, this));
|
||||
|
||||
@@ -502,9 +502,7 @@ void NodeTraverser::resolve_jobs(NodeValue &val)
|
||||
}
|
||||
|
||||
val.set_value(tex);
|
||||
} else if (plugin::PluginJob *plugin_job =
|
||||
dynamic_cast<plugin::PluginJob *>(
|
||||
base_job)) {
|
||||
} else if (dynamic_cast<plugin::PluginJob *>(base_job)) {
|
||||
VideoParams tex_params = job_tex->params();
|
||||
// Force internal working format (F32) for plugin processing,
|
||||
// matching FootageJob/GenerateJob behavior.
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
/* Render backend plugin ABI (oakgl / oakvulkan dlopen) */
|
||||
_ZN5olive8Renderer*;
|
||||
_ZTVN5olive8RendererE;
|
||||
_ZTIN5olive8RendererE;
|
||||
_ZTSN5olive8RendererE;
|
||||
_ZN5olive11VideoParams19get_bytes_per_pixelE*;
|
||||
_ZN5olive11VideoParams21get_bytes_per_channelE*;
|
||||
_ZN5olive13FileFunctions19read_file_as_stringE*;
|
||||
|
||||
@@ -37,8 +37,11 @@ static const char *pixel_depth_to_ofx(core::PixelFormat format)
|
||||
return kOfxBitDepthShort;
|
||||
case core::PixelFormat::f16:
|
||||
return kOfxBitDepthHalf;
|
||||
default:
|
||||
break;
|
||||
case core::PixelFormat::f32:
|
||||
return kOfxBitDepthFloat;
|
||||
case core::PixelFormat::u10:
|
||||
case core::PixelFormat::invalid:
|
||||
case core::PixelFormat::count:
|
||||
break;
|
||||
|
||||
@@ -79,18 +79,18 @@ public:
|
||||
makeDescriptor(const std::string &bundle_path,
|
||||
OFX::Host::ImageEffect::ImageEffectPlugin *plugin) override;
|
||||
/// vmessage
|
||||
virtual OfxStatus vmessage(const char *type, const char *id,
|
||||
const char *format, va_list args);
|
||||
OfxStatus vmessage(const char *type, const char *id,
|
||||
const char *format, va_list args) override;
|
||||
|
||||
/// vmessage
|
||||
virtual OfxStatus setPersistentMessage(const char *type, const char *id,
|
||||
const char *format, va_list args);
|
||||
OfxStatus setPersistentMessage(const char *type, const char *id,
|
||||
const char *format, va_list args) override;
|
||||
/// vmessage
|
||||
virtual OfxStatus clearPersistentMessage();
|
||||
OfxStatus clearPersistentMessage() override;
|
||||
|
||||
#ifdef OFX_SUPPORTS_OPENGLRENDER
|
||||
/// @see OfxImageEffectOpenGLRenderSuiteV1.flushResources()
|
||||
virtual OfxStatus flushOpenGLResources() const
|
||||
virtual OfxStatus flushOpenGLResources() const override
|
||||
{
|
||||
return kOfxStatFailed;
|
||||
};
|
||||
|
||||
@@ -209,13 +209,13 @@ public:
|
||||
|
||||
/// get the current time on the timeline. This is not necessarily the same
|
||||
/// time as being passed to an action (eg render)
|
||||
virtual double timeLineGetTime();
|
||||
double timeLineGetTime() override;
|
||||
|
||||
/// set the timeline to a specific time
|
||||
virtual void timeLineGotoTime(double t);
|
||||
void timeLineGotoTime(double t) override;
|
||||
|
||||
/// get the first and last times available on the effect's timeline
|
||||
virtual void timeLineGetBounds(double &t1, double &t2);
|
||||
void timeLineGetBounds(double &t1, double &t2) override;
|
||||
|
||||
void setCustomInArgs(const std::string &action,
|
||||
OFX::Host::Property::Set &in_args) override;
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(int &a)
|
||||
OfxStatus get(int &a) override
|
||||
{
|
||||
if (!node_) {
|
||||
std::lock_guard<std::mutex> lock(no_node_mutex_);
|
||||
@@ -151,7 +151,7 @@ public:
|
||||
a = 0;
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus get(OfxTime time, int &data)
|
||||
OfxStatus get(OfxTime time, int &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
std::lock_guard<std::mutex> lock(no_node_mutex_);
|
||||
@@ -170,7 +170,7 @@ public:
|
||||
data = 0;
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus set(int data)
|
||||
OfxStatus set(int data) override
|
||||
{
|
||||
if (!node_) {
|
||||
std::lock_guard<std::mutex> lock(no_node_mutex_);
|
||||
@@ -186,7 +186,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, int data)
|
||||
OfxStatus set(OfxTime time, int data) override
|
||||
{
|
||||
if (!node_) {
|
||||
std::lock_guard<std::mutex> lock(no_node_mutex_);
|
||||
@@ -233,7 +233,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(double &data)
|
||||
OfxStatus get(double &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : 0.0;
|
||||
@@ -253,7 +253,7 @@ public:
|
||||
data = 0.0;
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus get(OfxTime time, double &data)
|
||||
OfxStatus get(OfxTime time, double &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : 0.0;
|
||||
@@ -273,7 +273,7 @@ public:
|
||||
data = 0.0;
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus set(double data)
|
||||
OfxStatus set(double data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data;
|
||||
@@ -293,7 +293,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, double data)
|
||||
OfxStatus set(OfxTime time, double data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data;
|
||||
@@ -313,11 +313,11 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus derive(OfxTime, double &)
|
||||
OfxStatus derive(OfxTime, double &) override
|
||||
{
|
||||
return kOfxStatErrUnsupported;
|
||||
}
|
||||
OfxStatus integrate(OfxTime, OfxTime, double &)
|
||||
OfxStatus integrate(OfxTime, OfxTime, double &) override
|
||||
{
|
||||
return kOfxStatErrUnsupported;
|
||||
}
|
||||
@@ -352,7 +352,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(bool &data)
|
||||
OfxStatus get(bool &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : false;
|
||||
@@ -367,7 +367,7 @@ public:
|
||||
data = default_value();
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus get(OfxTime time, bool &data)
|
||||
OfxStatus get(OfxTime time, bool &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : false;
|
||||
@@ -392,7 +392,7 @@ public:
|
||||
data = default_value();
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(bool data)
|
||||
OfxStatus set(bool data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data;
|
||||
@@ -406,7 +406,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, bool data)
|
||||
OfxStatus set(OfxTime time, bool data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data;
|
||||
@@ -452,7 +452,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(int &data)
|
||||
OfxStatus get(int &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : 0;
|
||||
@@ -467,7 +467,7 @@ public:
|
||||
data = 0;
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus get(OfxTime time, int &data)
|
||||
OfxStatus get(OfxTime time, int &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : 0;
|
||||
@@ -482,7 +482,7 @@ public:
|
||||
data = 0;
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus set(int data)
|
||||
OfxStatus set(int data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data;
|
||||
@@ -496,7 +496,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, int data)
|
||||
OfxStatus set(OfxTime time, int data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data;
|
||||
@@ -534,7 +534,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(double &r, double &g, double &b, double &a)
|
||||
OfxStatus get(double &r, double &g, double &b, double &a) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -557,7 +557,7 @@ public:
|
||||
a = static_cast<double>(c.alpha());
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus get(OfxTime time, double &r, double &g, double &b, double &a)
|
||||
OfxStatus get(OfxTime time, double &r, double &g, double &b, double &a) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -581,7 +581,7 @@ public:
|
||||
a = static_cast<double>(c.alpha());
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(double r, double g, double b, double a)
|
||||
OfxStatus set(double r, double g, double b, double a) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = r;
|
||||
@@ -599,7 +599,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, double r, double g, double b, double a)
|
||||
OfxStatus set(OfxTime time, double r, double g, double b, double a) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = r;
|
||||
@@ -646,7 +646,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(double &r, double &g, double &b)
|
||||
OfxStatus get(double &r, double &g, double &b) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -667,7 +667,7 @@ public:
|
||||
b = static_cast<double>(c.blue());
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus get(OfxTime time, double &r, double &g, double &b)
|
||||
OfxStatus get(OfxTime time, double &r, double &g, double &b) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -689,7 +689,7 @@ public:
|
||||
b = static_cast<double>(c.blue());
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(double r, double g, double b)
|
||||
OfxStatus set(double r, double g, double b) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = r;
|
||||
@@ -706,7 +706,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, double r, double g, double b)
|
||||
OfxStatus set(OfxTime time, double r, double g, double b) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = r;
|
||||
@@ -751,7 +751,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(double &x, double &y)
|
||||
OfxStatus get(double &x, double &y) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -774,7 +774,7 @@ public:
|
||||
}
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus get(OfxTime time, double &x, double &y)
|
||||
OfxStatus get(OfxTime time, double &x, double &y) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -798,7 +798,7 @@ public:
|
||||
}
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(double x, double y)
|
||||
OfxStatus set(double x, double y) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = x;
|
||||
@@ -820,7 +820,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, double x, double y)
|
||||
OfxStatus set(OfxTime time, double x, double y) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = x;
|
||||
@@ -869,7 +869,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(int &x, int &y)
|
||||
OfxStatus get(int &x, int &y) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -886,7 +886,7 @@ public:
|
||||
y = static_cast<int>(vec.y());
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus get(OfxTime time, int &x, int &y)
|
||||
OfxStatus get(OfxTime time, int &x, int &y) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -904,7 +904,7 @@ public:
|
||||
y = static_cast<int>(vec.y());
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(int x, int y)
|
||||
OfxStatus set(int x, int y) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = x;
|
||||
@@ -919,7 +919,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, int x, int y)
|
||||
OfxStatus set(OfxTime time, int x, int y) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = x;
|
||||
@@ -961,7 +961,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(double &x, double &y, double &z)
|
||||
OfxStatus get(double &x, double &y, double &z) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -987,7 +987,7 @@ public:
|
||||
}
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus get(OfxTime time, double &x, double &y, double &z)
|
||||
OfxStatus get(OfxTime time, double &x, double &y, double &z) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -1014,7 +1014,7 @@ public:
|
||||
}
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(double x, double y, double z)
|
||||
OfxStatus set(double x, double y, double z) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = x;
|
||||
@@ -1038,7 +1038,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, double x, double y, double z)
|
||||
OfxStatus set(OfxTime time, double x, double y, double z) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = x;
|
||||
@@ -1091,7 +1091,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(int &x, int &y, int &z)
|
||||
OfxStatus get(int &x, int &y, int &z) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -1110,7 +1110,7 @@ public:
|
||||
z = static_cast<int>(vec.z());
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus get(OfxTime time, int &x, int &y, int &z)
|
||||
OfxStatus get(OfxTime time, int &x, int &y, int &z) override
|
||||
{
|
||||
if (!node_) {
|
||||
if (has_value_) {
|
||||
@@ -1130,7 +1130,7 @@ public:
|
||||
z = static_cast<int>(vec.z());
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(int x, int y, int z)
|
||||
OfxStatus set(int x, int y, int z) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = x;
|
||||
@@ -1146,7 +1146,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, int x, int y, int z)
|
||||
OfxStatus set(OfxTime time, int x, int y, int z) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_[0] = x;
|
||||
@@ -1198,7 +1198,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(std::string &data)
|
||||
OfxStatus get(std::string &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : std::string();
|
||||
@@ -1213,7 +1213,7 @@ public:
|
||||
data.clear();
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus get(OfxTime time, std::string &data)
|
||||
OfxStatus get(OfxTime time, std::string &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : std::string();
|
||||
@@ -1228,7 +1228,7 @@ public:
|
||||
data.clear();
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus set(const char *data)
|
||||
OfxStatus set(const char *data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data ? data : "";
|
||||
@@ -1243,7 +1243,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, const char *data)
|
||||
OfxStatus set(OfxTime time, const char *data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data ? data : "";
|
||||
@@ -1282,7 +1282,7 @@ public:
|
||||
{
|
||||
node_ = new_node;
|
||||
}
|
||||
OfxStatus get(std::string &data)
|
||||
OfxStatus get(std::string &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : std::string();
|
||||
@@ -1301,7 +1301,7 @@ public:
|
||||
data.clear();
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus get(OfxTime time, std::string &data)
|
||||
OfxStatus get(OfxTime time, std::string &data) override
|
||||
{
|
||||
if (!node_) {
|
||||
data = has_value_ ? value_ : std::string();
|
||||
@@ -1320,7 +1320,7 @@ public:
|
||||
data.clear();
|
||||
return kOfxStatErrValue;
|
||||
}
|
||||
OfxStatus set(const char *data)
|
||||
OfxStatus set(const char *data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data ? data : "";
|
||||
@@ -1335,7 +1335,7 @@ public:
|
||||
submit_undo_command(node_, command, param_change_label(descriptor_));
|
||||
return kOfxStatOK;
|
||||
}
|
||||
OfxStatus set(OfxTime time, const char *data)
|
||||
OfxStatus set(OfxTime time, const char *data) override
|
||||
{
|
||||
if (!node_) {
|
||||
value_ = data ? data : "";
|
||||
|
||||
@@ -37,7 +37,7 @@ void AudioWaveformCache::write_waveform(const TimeRange &range,
|
||||
const AudioVisualWaveform *waveform)
|
||||
{
|
||||
// Write each valid range to the segments
|
||||
foreach (const TimeRange &r, valid_ranges) {
|
||||
for (const TimeRange &r : valid_ranges) {
|
||||
if (waveform) {
|
||||
waveforms_->overwrite_sums(*waveform, r.in(), r.in() - range.in(),
|
||||
r.length());
|
||||
|
||||
@@ -18,7 +18,11 @@ DynamicRenderer::DynamicRenderer(const QString &backend, QObject *parent)
|
||||
}
|
||||
|
||||
// Tears down the backend in the reverse order used by Load(): release renderer
|
||||
// resources, destroy the opaque backend object, then unload the shared library.
|
||||
// resources, then destroy the opaque backend object. The shared library itself
|
||||
// is deliberately NOT unloaded: multiple DynamicRenderer instances can wrap the
|
||||
// same backend library, and one instance's dlclose can unmap code that other
|
||||
// instances (or Qt) still reference, producing calls into unmapped memory.
|
||||
// Backend libraries stay mapped until process exit.
|
||||
DynamicRenderer::~DynamicRenderer()
|
||||
{
|
||||
destroy();
|
||||
@@ -27,9 +31,6 @@ DynamicRenderer::~DynamicRenderer()
|
||||
destroy_(handle_);
|
||||
handle_ = nullptr;
|
||||
}
|
||||
if (library_.isLoaded()) {
|
||||
library_.unload();
|
||||
}
|
||||
}
|
||||
|
||||
// Builds the private backend library path for the current platform.
|
||||
|
||||
@@ -373,7 +373,7 @@ bool DiskCacheFolder::delete_least_recent()
|
||||
auto hash_to_delete = disk_data_.begin();
|
||||
|
||||
if (disk_data_.begin() != disk_data_.end()) {
|
||||
for (auto it = disk_data_.begin() + 1; it != disk_data_.end(); it++) {
|
||||
for (auto it = std::next(disk_data_.begin()); it != disk_data_.end(); it++) {
|
||||
if (it->access_time < hash_to_delete->access_time) {
|
||||
hash_to_delete = it;
|
||||
}
|
||||
|
||||
@@ -558,6 +558,8 @@ void OpenGLRenderer::blit(QVariant s, AcceleratedJob &a_job,
|
||||
// over/underflows if the number is large enough, but the likelihood of that is quite low.
|
||||
functions_->glUniform1i(variable_location, value.to_int());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case NodeValue::k_float:
|
||||
// kFloat technically specifies a double but as above, OpenGL doesn't support those.
|
||||
functions_->glUniform1f(variable_location, value.to_double());
|
||||
@@ -828,7 +830,7 @@ void OpenGLRenderer::blit(QVariant s, AcceleratedJob &a_job,
|
||||
vert_vbo.destroy();
|
||||
vao.release();
|
||||
vao.destroy();
|
||||
} catch (std::bad_cast e) {
|
||||
} catch (const std::bad_cast &e) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,7 +977,6 @@ GLuint OpenGLRenderer::compile_shader(GLenum type, const QString &code)
|
||||
{
|
||||
const bool is_gles = context_ && context_->isOpenGLES();
|
||||
const int major = context_ ? context_->format().majorVersion() : 0;
|
||||
const int minor = context_ ? context_->format().minorVersion() : 0;
|
||||
const bool is_gles2 = is_gles && (major < 3);
|
||||
const QString gles_preamble =
|
||||
is_gles2 ? QStringLiteral("#version 100\n\n"
|
||||
|
||||
@@ -191,7 +191,7 @@ void PlaybackCache::draw(QPainter *p, const Rational &start, double scale,
|
||||
{
|
||||
p->fillRect(rect, Qt::red);
|
||||
|
||||
foreach (const TimeRange &range, get_validated_ranges()) {
|
||||
for (const TimeRange &range : get_validated_ranges()) {
|
||||
int range_left = rect.left() + (range.in() - start).to_double() * scale;
|
||||
if (range_left >= rect.right()) {
|
||||
continue;
|
||||
@@ -288,11 +288,11 @@ TimeRangeList PlaybackCache::get_invalidated_ranges(TimeRange intersecting) cons
|
||||
|
||||
invalidated.insert(intersecting);
|
||||
|
||||
foreach (const TimeRange &range, validated_) {
|
||||
for (const TimeRange &range : validated_) {
|
||||
invalidated.remove(range);
|
||||
}
|
||||
|
||||
foreach (const TimeRange &range, passthroughs_) {
|
||||
for (const TimeRange &range : passthroughs_) {
|
||||
invalidated.remove(range);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,9 +69,9 @@ static int
|
||||
get_ofx_av_pixel_format(const OFX::Host::ImageEffect::Image &image,
|
||||
int *bytes_per_pixel)
|
||||
{
|
||||
const std::string &depth =
|
||||
[[maybe_unused]] const std::string &depth =
|
||||
image.getStringProperty(kOfxImageEffectPropPixelDepth);
|
||||
const std::string &components =
|
||||
[[maybe_unused]] const std::string &components =
|
||||
image.getStringProperty(kOfxImageEffectPropComponents);
|
||||
|
||||
olive::core::PixelFormat pixel_format = olive::core::PixelFormat::invalid;
|
||||
@@ -289,7 +289,7 @@ get_destination_av_pixel_format(const olive::VideoParams ¶ms);
|
||||
|
||||
// 作用:读取 clip 偏好(像素深度与分量)并更新 VideoParams。
|
||||
// Purpose: Apply clip preferences (depth/components) into VideoParams.
|
||||
static bool
|
||||
[[maybe_unused]] static bool
|
||||
apply_clip_preferences_to_params(const OFX::Host::ImageEffect::ClipInstance &clip,
|
||||
olive::VideoParams *params)
|
||||
{
|
||||
@@ -298,7 +298,7 @@ apply_clip_preferences_to_params(const OFX::Host::ImageEffect::ClipInstance &cli
|
||||
}
|
||||
|
||||
olive::core::PixelFormat format = olive::core::PixelFormat::invalid;
|
||||
const std::string &depth = clip.getPixelDepth();
|
||||
[[maybe_unused]] const std::string &depth = clip.getPixelDepth();
|
||||
if (depth == kOfxBitDepthByte) {
|
||||
format = olive::core::PixelFormat::u8;
|
||||
} else if (depth == kOfxBitDepthShort) {
|
||||
@@ -310,7 +310,7 @@ apply_clip_preferences_to_params(const OFX::Host::ImageEffect::ClipInstance &cli
|
||||
}
|
||||
|
||||
int channels = 0;
|
||||
const std::string &components = clip.getComponents();
|
||||
[[maybe_unused]] const std::string &components = clip.getComponents();
|
||||
if (components == kOfxImageComponentRGBA) {
|
||||
channels = 4;
|
||||
} else if (components == kOfxImageComponentRGB) {
|
||||
@@ -359,6 +359,8 @@ static const char *ofx_depth_from_pixel_format(olive::core::PixelFormat format)
|
||||
return kOfxBitDepthShort;
|
||||
case olive::core::PixelFormat::f16:
|
||||
return kOfxBitDepthHalf;
|
||||
default:
|
||||
break;
|
||||
case olive::core::PixelFormat::f32:
|
||||
return kOfxBitDepthFloat;
|
||||
case olive::core::PixelFormat::invalid:
|
||||
@@ -460,7 +462,7 @@ static bool params_convertible(const olive::VideoParams ¶ms)
|
||||
|
||||
// 作用:在 clip 偏好无效时,选择一个插件支持的输出格式。
|
||||
// Purpose: Pick a supported output format when clip preferences are invalid.
|
||||
static void
|
||||
[[maybe_unused]] static void
|
||||
choose_supported_output_params(const OFX::Host::ImageEffect::Instance &instance,
|
||||
const OFX::Host::ImageEffect::ClipInstance &clip,
|
||||
const olive::VideoParams &preferred,
|
||||
@@ -522,7 +524,7 @@ convert_texture_for_params(olive::TexturePtr src,
|
||||
|
||||
// 作用:根据插件能力与偏好选择输入格式并执行转换。
|
||||
// Purpose: Select a supported input format and convert texture for the clip.
|
||||
static olive::TexturePtr
|
||||
[[maybe_unused]] static olive::TexturePtr
|
||||
convert_texture_for_clip(const OFX::Host::ImageEffect::Instance &instance,
|
||||
const OFX::Host::ImageEffect::ClipInstance &clip,
|
||||
olive::TexturePtr src,
|
||||
@@ -670,7 +672,7 @@ convert_texture_for_clip(const OFX::Host::ImageEffect::Instance &instance,
|
||||
|
||||
// 作用:从 OFX Image 复制数据到 AVFrame(按图像属性推导格式)。
|
||||
// Purpose: Copy OFX Image data into an AVFrame with inferred format.
|
||||
static olive::AVFramePtr
|
||||
[[maybe_unused]] static olive::AVFramePtr
|
||||
create_avframe_from_ofx_image(OFX::Host::ImageEffect::Image &image)
|
||||
{
|
||||
void *data_ptr = image.getPointerProperty(kOfxImagePropData);
|
||||
@@ -1323,10 +1325,9 @@ static void log_image_props(const char *label,
|
||||
int rod[4] = { 0, 0, 0, 0 };
|
||||
image->getIntPropertyN(kOfxImagePropBounds, bounds, 4);
|
||||
image->getIntPropertyN(kOfxImagePropRegionOfDefinition, rod, 4);
|
||||
const int row_bytes = image->getIntProperty(kOfxImagePropRowBytes);
|
||||
const std::string &depth =
|
||||
[[maybe_unused]] const std::string &depth =
|
||||
image->getStringProperty(kOfxImageEffectPropPixelDepth);
|
||||
const std::string &components =
|
||||
[[maybe_unused]] const std::string &components =
|
||||
image->getStringProperty(kOfxImageEffectPropComponents);
|
||||
/*qWarning().noquote()
|
||||
<< "OFX image props" << label
|
||||
@@ -1370,7 +1371,7 @@ static void schedule_error_dialog_and_undo(const QString &message)
|
||||
}
|
||||
}
|
||||
|
||||
static olive::AVFramePtr download_texture_to_frame(const olive::TexturePtr &tex)
|
||||
[[maybe_unused]] static olive::AVFramePtr download_texture_to_frame(const olive::TexturePtr &tex)
|
||||
{
|
||||
if (!tex || tex->is_dummy() || !tex->renderer()) {
|
||||
return nullptr;
|
||||
@@ -1425,7 +1426,7 @@ select_best_plugin_input_format(const OFX::Host::ImageEffect::Descriptor &desc)
|
||||
bool supports_f16 = false;
|
||||
|
||||
for (int i = 0; i < dim; ++i) {
|
||||
const std::string &depth =
|
||||
[[maybe_unused]] const std::string &depth =
|
||||
props.getStringProperty(kOfxImageEffectPropSupportedPixelDepths, i);
|
||||
if (depth == kOfxBitDepthFloat) {
|
||||
supports_f32 = true;
|
||||
@@ -1541,8 +1542,8 @@ void olive::plugin::PluginRenderer::render_plugin(
|
||||
if (!tex->is_dummy() && tex->renderer()) {
|
||||
return true;
|
||||
}
|
||||
AVFramePtr frame = tex->frame();
|
||||
return frame && frame->data(0);
|
||||
AVFramePtr av_frame = tex->frame();
|
||||
return av_frame && av_frame->data(0);
|
||||
};
|
||||
std::map<std::string, TexturePtr> input_textures;
|
||||
std::map<std::string, OliveClipInstance *> input_clips;
|
||||
@@ -1817,12 +1818,10 @@ void olive::plugin::PluginRenderer::render_plugin(
|
||||
}
|
||||
// Diagnostic: peek at first few pixels
|
||||
void *img_data = output_image->getPointerProperty(kOfxImagePropData);
|
||||
bool img_black = true;
|
||||
if (img_data) {
|
||||
float *f = static_cast<float *>(img_data);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (f[i] != 0.0f) {
|
||||
img_black = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ void RenderJobTracker::insert(const TimeRange &range, JobTime job_time)
|
||||
|
||||
void RenderJobTracker::insert(const TimeRangeList &ranges, JobTime job_time)
|
||||
{
|
||||
foreach (const TimeRange &r, ranges) {
|
||||
for (const TimeRange &r : ranges) {
|
||||
insert(r, job_time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ bool connect_node_event(olive::Node *node, int32_t event_id,
|
||||
case OAKENGINE_EVENT_NODE_INPUT_DISCONNECTED: {
|
||||
const bool connected =
|
||||
event_id == OAKENGINE_EVENT_NODE_INPUT_CONNECTED;
|
||||
auto deliver = [fn, userdata, node, connected, event_id](
|
||||
auto deliver = [fn, userdata, node, event_id](
|
||||
Node *output, const NodeInput &input) {
|
||||
const QByteArray utf = input.input().toUtf8();
|
||||
invoke(fn, userdata, event_id, node, input.element(), 0, output, 0,
|
||||
|
||||
@@ -328,7 +328,11 @@ bool video_stream_at(const olive::Footage *f, int index,
|
||||
// Internal cross-family accessor (not part of the public C ABI): returns
|
||||
// the borrowed project node of an import handle, or nullptr for probe
|
||||
// handles and NULL. Used by the timeline editing primitives.
|
||||
#if defined(_WIN32)
|
||||
extern "C" void *
|
||||
#else
|
||||
extern "C" __attribute__((visibility("hidden"))) void *
|
||||
#endif
|
||||
oakengine_capi_footage_node(OakEngineFootage *h)
|
||||
{
|
||||
if (!h) {
|
||||
|
||||
@@ -61,13 +61,13 @@ int oakengine_plugin_set_progress_reporter_factory(
|
||||
oakengine_plugin_reporter_create_fn create,
|
||||
oakengine_plugin_reporter_destroy_fn destroy,
|
||||
oakengine_plugin_reporter_is_cancelled_fn is_cancelled,
|
||||
oakengine_plugin_reporter_set_progress_fn set_progress,
|
||||
oakengine_plugin_reporter_set_progress_fn set_progress_fn,
|
||||
void *userdata)
|
||||
{
|
||||
g_reporter_create = create;
|
||||
g_reporter_destroy = destroy;
|
||||
g_reporter_is_cancelled = is_cancelled;
|
||||
g_reporter_set_progress = set_progress;
|
||||
g_reporter_set_progress = set_progress_fn;
|
||||
g_reporter_userdata = userdata;
|
||||
|
||||
// Register factory with the engine.
|
||||
@@ -90,12 +90,12 @@ int oakengine_plugin_set_progress_reporter_factory(
|
||||
CAdapter(void *reporter,
|
||||
oakengine_plugin_reporter_destroy_fn destroy,
|
||||
oakengine_plugin_reporter_is_cancelled_fn is_cancelled,
|
||||
oakengine_plugin_reporter_set_progress_fn set_progress,
|
||||
oakengine_plugin_reporter_set_progress_fn set_progress_fn,
|
||||
void *userdata)
|
||||
: PluginProgressReporter()
|
||||
, reporter_(reporter)
|
||||
, destroy_(destroy)
|
||||
, set_progress_(set_progress)
|
||||
, set_progress_(set_progress_fn)
|
||||
, userdata_(userdata) {}
|
||||
~CAdapter() override
|
||||
{
|
||||
|
||||
@@ -2390,7 +2390,9 @@ int oakengine_clip_set_media_in(OakEngineClip *self, int64_t media_in_ts,
|
||||
set_seq_error(QStringLiteral("invalid clip handle"));
|
||||
return OAKENGINE_E_INVALID;
|
||||
}
|
||||
|
||||
olive::ClipBlock *clip = reinterpret_cast<olive::ClipBlock *>(self);
|
||||
|
||||
const olive::Sequence *sequence =
|
||||
clip->track() ? clip->track()->sequence() : nullptr;
|
||||
if (!sequence) {
|
||||
@@ -2427,7 +2429,9 @@ int oakengine_clip_set_media_in_rational(OakEngineClip *self, int64_t num,
|
||||
set_seq_error(QStringLiteral("invalid rational denominator"));
|
||||
return OAKENGINE_E_INVALID;
|
||||
}
|
||||
|
||||
olive::ClipBlock *clip = reinterpret_cast<olive::ClipBlock *>(self);
|
||||
|
||||
const olive::Rational time(static_cast<int>(num), static_cast<int>(den));
|
||||
if (undoable) {
|
||||
push_or_run(new olive::BlockSetMediaInCommand(clip, time),
|
||||
@@ -2444,7 +2448,7 @@ void oakengine_clip_request_invalidate(OakEngineClip *self, int64_t in_ts,
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
olive::ClipBlock *clip = reinterpret_cast<olive::ClipBlock *>(self);
|
||||
|
||||
// Forward to the clip's cache invalidation.
|
||||
Q_UNUSED(in_ts)
|
||||
Q_UNUSED(out_ts)
|
||||
@@ -2489,7 +2493,9 @@ void oakengine_clip_request_invalidate_connected(OakEngineClip *self,
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
olive::ClipBlock *clip = reinterpret_cast<olive::ClipBlock *>(self);
|
||||
|
||||
olive::TimeRange intersect;
|
||||
if (in_den != 0 && out_den != 0) {
|
||||
intersect = olive::TimeRange(
|
||||
|
||||
@@ -410,6 +410,8 @@ private:
|
||||
it.key());
|
||||
}
|
||||
|
||||
log_error(QStringLiteral("LoadGraph: deserialized ok, %1 nodes")
|
||||
.arg(node_by_token.size()));
|
||||
QJsonObject ack;
|
||||
ack["type"] = QStringLiteral("graph_loaded");
|
||||
ack["nodes"] = node_by_token.size();
|
||||
@@ -449,6 +451,9 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
log_error(QStringLiteral("render_frame: ticket %1 node %2")
|
||||
.arg(message.ticket_id)
|
||||
.arg(message.node_uuid));
|
||||
olive::Node *node = find_node(message.node_uuid);
|
||||
if (!node) {
|
||||
*response =
|
||||
@@ -726,6 +731,17 @@ olive::Renderer *create_renderer(const char *backend, bool *valid)
|
||||
}
|
||||
if (!ctx || !ctx->isValid()) {
|
||||
renderer_valid = false;
|
||||
} else {
|
||||
// Windows CI runners without a GPU hand back the GDI software
|
||||
// OpenGL 1.1 implementation here; log what we actually got so a
|
||||
// later crash in 3.2 core calls is attributable.
|
||||
log_error(QStringLiteral("OpenGL context version: %1.%2 (%3)")
|
||||
.arg(ctx->format().majorVersion())
|
||||
.arg(ctx->format().minorVersion())
|
||||
.arg(ctx->format().profile() ==
|
||||
QSurfaceFormat::CoreProfile ?
|
||||
"core" :
|
||||
"compatibility/none"));
|
||||
}
|
||||
}
|
||||
if (!renderer_valid) {
|
||||
@@ -849,7 +865,11 @@ int oakengine_worker_session_shutdown_requested(const OakWorkerSession *self)
|
||||
|
||||
int oakengine_worker_main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
||||
// QT_OPENGL (e.g. "software" with Mesa opengl32sw.dll on GPU-less CI)
|
||||
// takes precedence over this default.
|
||||
if (!qEnvironmentVariableIsSet("QT_OPENGL")) {
|
||||
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
||||
}
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||
install_surface_format();
|
||||
|
||||
|
||||
@@ -211,6 +211,21 @@ bool ExportTask::run()
|
||||
|
||||
bool ExportTask::frame_downloaded(FramePtr f, const Rational &time)
|
||||
{
|
||||
// The worker pool finishes tickets without a result when no worker is
|
||||
// available (or every worker crashed). Grinding through the whole
|
||||
// timeline at several seconds per dead worker looks like a hang, so
|
||||
// fail the export after a short streak of missing frames.
|
||||
if (!f) {
|
||||
if (++null_frame_streak_ >= 8) {
|
||||
set_error(tr("Render workers failed to deliver %1 consecutive "
|
||||
"frames; aborting export")
|
||||
.arg(null_frame_streak_));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
null_frame_streak_ = 0;
|
||||
}
|
||||
|
||||
Rational actual_time = time - export_range_.in();
|
||||
|
||||
time_map_.insert(actual_time, f);
|
||||
|
||||
@@ -74,6 +74,8 @@ private:
|
||||
|
||||
int64_t frame_time_;
|
||||
|
||||
int null_frame_streak_ = 0;
|
||||
|
||||
Rational audio_time_;
|
||||
|
||||
TimeRange export_range_;
|
||||
|
||||
@@ -109,7 +109,7 @@ bool LoadOTIOTask::run()
|
||||
// Generate a list of sequences with the same names as the timelines.
|
||||
// Assumes each timeline has a unique name.
|
||||
int unnamed_sequence_count = 0;
|
||||
foreach (auto timeline, timelines) {
|
||||
for (auto timeline : timelines) {
|
||||
Sequence *sequence = new Sequence();
|
||||
if (!timeline->name().empty()) {
|
||||
sequence->set_label(QString::fromStdString(timeline->name()));
|
||||
@@ -124,7 +124,7 @@ bool LoadOTIOTask::run()
|
||||
timeline_sequnce_map.insert(timeline, sequence);
|
||||
|
||||
// Get number of clips for loading bar
|
||||
foreach (auto track, timeline->tracks()->children()) {
|
||||
for (auto track : timeline->tracks()->children()) {
|
||||
auto otio_track = static_cast<OTIO::Track *>(track.value);
|
||||
number_of_clips += otio_track->children().size();
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ bool SaveOTIOTask::run()
|
||||
serialized.push_back(otio_timeline);
|
||||
} else {
|
||||
// Delete all existing timelines
|
||||
foreach (auto s, serialized) {
|
||||
for (auto s : serialized) {
|
||||
s->possibly_delete();
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ bool SaveOTIOTask::run()
|
||||
collection->possibly_delete();
|
||||
|
||||
// Delete all existing timelines
|
||||
foreach (auto s, serialized) {
|
||||
for (auto s : serialized) {
|
||||
s->possibly_delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ bool RenderTask::render(ColorManager *manager, const TimeRangeList &video_range,
|
||||
|
||||
// Store real time before any rendering takes place
|
||||
// Queue audio jobs
|
||||
foreach (const TimeRange &range, audio_range) {
|
||||
for (const TimeRange &range : audio_range) {
|
||||
// Don't count audio progress, since it's generally a lot faster than video and is weighted at
|
||||
// 50%, which makes the progress bar look weird to the uninitiated
|
||||
//total_length += r.length().toDouble();
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#if defined(_WIN32)
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@@ -113,20 +114,18 @@ static void test_open_folder_handle(void)
|
||||
EXPECT_TRUE(empty_folder == folder);
|
||||
|
||||
// A different path opens a distinct folder.
|
||||
char tmp[256];
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
char tmp[512];
|
||||
#if defined(_WIN32)
|
||||
"%s\\oakengine_disk_test_folder_XXXXXX",
|
||||
#else
|
||||
"%s/oakengine_disk_test_folder_XXXXXX",
|
||||
#endif
|
||||
getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
|
||||
|
||||
#if defined(_WIN32)
|
||||
char *tmpdir = _mktemp(tmp);
|
||||
EXPECT_TRUE(tmpdir != NULL);
|
||||
char base[MAX_PATH];
|
||||
const DWORD len = GetTempPathA(MAX_PATH, base);
|
||||
EXPECT_TRUE(len > 0 && len < MAX_PATH);
|
||||
snprintf(tmp, sizeof(tmp), "%soakengine_disk_test_folder_%lu", base,
|
||||
(unsigned long)GetCurrentProcessId());
|
||||
char *tmpdir = tmp;
|
||||
EXPECT_TRUE(_mkdir(tmpdir) == 0);
|
||||
#else
|
||||
snprintf(tmp, sizeof(tmp), "%s/oakengine_disk_test_folder_XXXXXX",
|
||||
getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
|
||||
char *tmpdir = mkdtemp(tmp);
|
||||
EXPECT_TRUE(tmpdir != NULL);
|
||||
#endif
|
||||
@@ -149,20 +148,18 @@ static void test_open_folder_handle(void)
|
||||
static void test_clear_cache(void)
|
||||
{
|
||||
// Create a temporary cache directory and seed it with a file.
|
||||
char path[256];
|
||||
snprintf(path, sizeof(path),
|
||||
char path[512];
|
||||
#if defined(_WIN32)
|
||||
"%s\\oakengine_disk_test_cache_XXXXXX",
|
||||
#else
|
||||
"%s/oakengine_disk_test_cache_XXXXXX",
|
||||
#endif
|
||||
getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
|
||||
|
||||
#if defined(_WIN32)
|
||||
char *tmpdir = _mktemp(path);
|
||||
EXPECT_TRUE(tmpdir != NULL);
|
||||
char base[MAX_PATH];
|
||||
const DWORD len = GetTempPathA(MAX_PATH, base);
|
||||
EXPECT_TRUE(len > 0 && len < MAX_PATH);
|
||||
snprintf(path, sizeof(path), "%soakengine_disk_test_cache_%lu", base,
|
||||
(unsigned long)GetCurrentProcessId());
|
||||
char *tmpdir = path;
|
||||
EXPECT_TRUE(_mkdir(tmpdir) == 0);
|
||||
#else
|
||||
snprintf(path, sizeof(path), "%s/oakengine_disk_test_cache_XXXXXX",
|
||||
getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
|
||||
char *tmpdir = mkdtemp(path);
|
||||
EXPECT_TRUE(tmpdir != NULL);
|
||||
#endif
|
||||
@@ -244,20 +241,18 @@ static void test_set_default_cache_path(void)
|
||||
EXPECT_TRUE(oakengine_disk_get_default_cache_path(original, sizeof(original)) >
|
||||
0);
|
||||
|
||||
char tmp[256];
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
char tmp[512];
|
||||
#if defined(_WIN32)
|
||||
"%s\\oakengine_disk_test_default_XXXXXX",
|
||||
#else
|
||||
"%s/oakengine_disk_test_default_XXXXXX",
|
||||
#endif
|
||||
getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
|
||||
|
||||
#if defined(_WIN32)
|
||||
char *tmpdir = _mktemp(tmp);
|
||||
EXPECT_TRUE(tmpdir != NULL);
|
||||
char base[MAX_PATH];
|
||||
const DWORD len = GetTempPathA(MAX_PATH, base);
|
||||
EXPECT_TRUE(len > 0 && len < MAX_PATH);
|
||||
snprintf(tmp, sizeof(tmp), "%soakengine_disk_test_default_%lu", base,
|
||||
(unsigned long)GetCurrentProcessId());
|
||||
char *tmpdir = tmp;
|
||||
EXPECT_TRUE(_mkdir(tmpdir) == 0);
|
||||
#else
|
||||
snprintf(tmp, sizeof(tmp), "%s/oakengine_disk_test_default_XXXXXX",
|
||||
getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
|
||||
char *tmpdir = mkdtemp(tmp);
|
||||
EXPECT_TRUE(tmpdir != NULL);
|
||||
#endif
|
||||
|
||||
@@ -49,12 +49,27 @@
|
||||
|
||||
static char g_tmpdir[4096];
|
||||
|
||||
// The engine stores project filenames with native separators (backslashes on
|
||||
// Windows); normalize a returned path to forward slashes before comparing
|
||||
// against the paths these tests construct.
|
||||
static void to_forward_slashes(char *s)
|
||||
{
|
||||
for (; *s; ++s) {
|
||||
if (*s == '\\') {
|
||||
*s = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void make_tmpdir(void)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
char base[MAX_PATH];
|
||||
const DWORD len = GetTempPathA(MAX_PATH, base);
|
||||
EXPECT_TRUE(len > 0 && len < MAX_PATH);
|
||||
// Resolve 8.3 short names (e.g. RUNNER~1) so string comparisons
|
||||
// against engine-canonicalized paths hold.
|
||||
GetLongPathNameA(base, base, MAX_PATH);
|
||||
snprintf(g_tmpdir, sizeof(g_tmpdir), "%soakengine_footage_test_%lu", base,
|
||||
(unsigned long)GetCurrentProcessId());
|
||||
EXPECT_TRUE(_mkdir(g_tmpdir) == 0);
|
||||
@@ -607,9 +622,11 @@ static void test_project_extras(void)
|
||||
// set_filename round-trips through the plain filename getter.
|
||||
char target[4096];
|
||||
snprintf(target, sizeof(target), "%s/roundtrip.ove", g_tmpdir);
|
||||
to_forward_slashes(target);
|
||||
EXPECT_TRUE(oakengine_project_set_filename(project, target) == OAKENGINE_OK);
|
||||
EXPECT_TRUE(oakengine_project_filename(project, buf, sizeof(buf)) > 0);
|
||||
EXPECT_TRUE(strcmp(buf, target) == 0);
|
||||
to_forward_slashes(buf);
|
||||
EXPECT_STREQ(buf, target);
|
||||
EXPECT_TRUE(oakengine_project_set_filename(project, NULL) ==
|
||||
OAKENGINE_E_INVALID);
|
||||
EXPECT_TRUE(oakengine_project_set_filename(NULL, target) ==
|
||||
|
||||
@@ -49,12 +49,27 @@
|
||||
|
||||
static char g_tmpdir[4096];
|
||||
|
||||
// The engine stores project filenames with native separators (backslashes on
|
||||
// Windows); normalize a returned path to forward slashes before comparing
|
||||
// against the paths these tests construct.
|
||||
static void to_forward_slashes(char *s)
|
||||
{
|
||||
for (; *s; ++s) {
|
||||
if (*s == '\\') {
|
||||
*s = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void make_tmpdir(void)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
char base[MAX_PATH];
|
||||
const DWORD len = GetTempPathA(MAX_PATH, base);
|
||||
EXPECT_TRUE(len > 0 && len < MAX_PATH);
|
||||
// Resolve 8.3 short names (e.g. RUNNER~1) so string comparisons
|
||||
// against engine-canonicalized paths hold.
|
||||
GetLongPathNameA(base, base, MAX_PATH);
|
||||
snprintf(g_tmpdir, sizeof(g_tmpdir), "%soakengine_init_test_%lu", base,
|
||||
(unsigned long)GetCurrentProcessId());
|
||||
EXPECT_TRUE(_mkdir(g_tmpdir) == 0);
|
||||
@@ -68,6 +83,10 @@ static void make_path(char *dst, size_t cap, const char *filename)
|
||||
{
|
||||
const int n = snprintf(dst, cap, "%s/%s", g_tmpdir, filename);
|
||||
EXPECT_TRUE(n > 0 && (size_t)n < cap);
|
||||
// g_tmpdir comes from GetTempPathA on Windows (backslashes); the
|
||||
// engine's forward-slash-normalized filename must compare against the
|
||||
// same form.
|
||||
to_forward_slashes(dst);
|
||||
}
|
||||
|
||||
static int file_exists(const char *path)
|
||||
@@ -231,7 +250,8 @@ static void test_sequence_and_save_load(void)
|
||||
char filename[4096];
|
||||
EXPECT_TRUE(oakengine_project_filename(p, filename, sizeof(filename)) ==
|
||||
(int)strlen(path));
|
||||
EXPECT_TRUE(strcmp(filename, path) == 0);
|
||||
to_forward_slashes(filename);
|
||||
EXPECT_STREQ(filename, path);
|
||||
|
||||
// Undo removes the sequence, redo brings the same object back.
|
||||
EXPECT_TRUE(oakengine_project_undo(p) == OAKENGINE_OK);
|
||||
@@ -258,7 +278,8 @@ static void test_sequence_and_save_load(void)
|
||||
EXPECT_TRUE(strcmp(name, "roundtrip") == 0);
|
||||
EXPECT_TRUE(oakengine_project_filename(q, filename, sizeof(filename)) ==
|
||||
(int)strlen(path));
|
||||
EXPECT_TRUE(strcmp(filename, path) == 0);
|
||||
to_forward_slashes(filename);
|
||||
EXPECT_STREQ(filename, path);
|
||||
|
||||
// The sequence survived the round trip, workarea included (the workarea
|
||||
// is serialized by ViewerOutput::save_custom()).
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
***/
|
||||
|
||||
#include <utility>
|
||||
#include "timelineundogeneral.h"
|
||||
|
||||
#include "node/block/clip/clip.h"
|
||||
@@ -322,7 +323,7 @@ void TrackListInsertGaps::prepare()
|
||||
QVector<Block *> blocks_to_append_gap_to;
|
||||
QVector<Track *> tracks_to_append_gap_to;
|
||||
|
||||
for (Track *track : qAsConst(working_tracks_)) {
|
||||
for (Track *track : std::as_const(working_tracks_)) {
|
||||
for (Block *b : track->blocks()) {
|
||||
if (dynamic_cast<GapBlock *>(b) && b->in() <= point_ &&
|
||||
b->out() >= point_) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
***/
|
||||
|
||||
#include <utility>
|
||||
#include "timelineundoripple.h"
|
||||
|
||||
#include "timelineundocommon.h"
|
||||
@@ -391,7 +392,7 @@ void TimelineRippleDeleteGapsAtRegionsCommand::prepare()
|
||||
QHash<Track *, QVector<RemovalRequest>> requested_gaps;
|
||||
|
||||
// Convert regions to gaps
|
||||
for (const QPair<Track *, TimeRange> ®ion : qAsConst(regions_)) {
|
||||
for (const QPair<Track *, TimeRange> ®ion : std::as_const(regions_)) {
|
||||
Track *track = region.first;
|
||||
const TimeRange &range = region.second;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user