build: split the engine into liboakengine.so; worker drops the UI entirely

Physical split: app/{audio,cli,codec,common,config,node,pluginSupport,
render,task,timeline,undo,tool,shaders} plus coreengine, version and
ui/icons+colorcoding move to a new top-level engine/ tree, built as
liboakengine.so (shared). The render backends (oakgl/oakvulkan) move
with it and link the engine library instead of embedding a static
render-core subset (libolive-rendercore is gone).

- oak-render-worker now links liboakengine instead of the whole
  libolive-editor object set: 336MB -> 2.9MB, no Qt Widgets UI
- the editor links liboakengine for the engine and keeps only UI
  objects in libolive-editor
- install/packaging: GNUInstallDirs libdir on Linux, bundle copy on
  macOS, oakengine.dll staged for NSIS, AppImage validation entry
- fix backend lookup for the new layout: DynamicRenderer searched
  ../app but backends now live in engine/; a stale pre-split liboakgl
  in the build tree got dlopened instead, re-initialized and later
  destroyed the interposed engine statics (full-suite segfault at
  DialogSequenceParameterTab, found via gdb watchpoint)
This commit is contained in:
2026-07-20 03:23:28 +08:00
parent 026ff94b5e
commit 28c4426236
604 changed files with 243 additions and 172 deletions
-55
View File
@@ -1,55 +0,0 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2022 Olive Team
# Modifications Copyright (C) 2025 mikesolar
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
target_sources(libolive-editor PRIVATE
cancelableobject.h
commandlineparser.cpp
commandlineparser.h
crashpadinterface.cpp
crashpadinterface.h
crashpadutils.h
current.cpp
current.h
debug.cpp
debug.h
decibel.h
define.h
ffmpegutils.cpp
ffmpegutils.h
filefunctions.cpp
filefunctions.h
html.cpp
html.h
jobtime.cpp
jobtime.h
lerp.h
memorypool.h
ocioutils.cpp
ocioutils.h
oiioutils.cpp
oiioutils.h
otioutils.h
playbackaudioclock.h
qtutils.cpp
qtutils.h
range.h
threadsafemap.h
tohex.h
util.h
xmlutils.cpp
xmlutils.h
)
-37
View File
@@ -1,37 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_AUTOSCROLL_H
#define OAK_AUTOSCROLL_H
#include "common/define.h"
namespace olive
{
class AutoScroll {
public:
enum Method { k_none, k_page, k_smooth };
};
}
#endif // OAK_AUTOSCROLL_H
-139
View File
@@ -1,139 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_AVFRAMEPTR_H
#define OAK_AVFRAMEPTR_H
#include <stdint.h>
#include <memory>
#include <ffmpeg_bridge/ffmpeg_bridge.h>
namespace olive
{
/**
* @brief C++ adapter around the ffmpeg_bridge frame handle
*
* Mirrors the AVFrame field access the codebase used to perform directly,
* but every operation goes through the pure C bridge API so the editor
* never touches FFmpeg itself. The underlying frame object always lives
* inside the bridge library.
*/
class AVFrame {
public:
AVFrame() :
handle_(fb_frame_alloc())
{
}
explicit AVFrame(FBFrame *handle) :
handle_(handle)
{
}
~AVFrame()
{
if (handle_) {
fb_frame_free(&handle_);
}
}
AVFrame(const AVFrame &) = delete;
AVFrame &operator=(const AVFrame &) = delete;
FBFrame *handle() const { return handle_; }
int width() const { return fb_frame_get_width(handle_); }
void set_width(int w) { fb_frame_set_width(handle_, w); }
int height() const { return fb_frame_get_height(handle_); }
void set_height(int h) { fb_frame_set_height(handle_, h); }
int format() const { return fb_frame_get_format(handle_); }
void set_format(int f) { fb_frame_set_format(handle_, f); }
int64_t pts() const { return fb_frame_get_pts(handle_); }
void set_pts(int64_t p) { fb_frame_set_pts(handle_, p); }
int64_t best_effort_timestamp() const
{
return fb_frame_get_best_effort_timestamp(handle_);
}
int nb_samples() const { return fb_frame_get_nb_samples(handle_); }
void set_nb_samples(int n) { fb_frame_set_nb_samples(handle_, n); }
int sample_rate() const { return fb_frame_get_sample_rate(handle_); }
void set_sample_rate(int r) { fb_frame_set_sample_rate(handle_, r); }
int color_range() const { return fb_frame_get_color_range(handle_); }
void set_color_range(int r) { fb_frame_set_color_range(handle_, r); }
int colorspace() const { return fb_frame_get_colorspace(handle_); }
void set_colorspace(int cs) { fb_frame_set_colorspace(handle_, cs); }
uint64_t channel_layout_mask() const
{
return fb_frame_get_channel_layout_mask(handle_);
}
void set_channel_layout_mask(uint64_t m)
{
fb_frame_set_channel_layout_mask(handle_, m);
}
bool is_hw() const { return fb_frame_is_hw(handle_) != 0; }
int hw_transfer_data(const AVFrame *src)
{
return fb_frame_hw_transfer_data(handle_, src->handle_);
}
int get_buffer(int align) { return fb_frame_get_buffer(handle_, align); }
int make_writable() { return fb_frame_make_writable(handle_); }
uint8_t *data(int plane) { return fb_frame_get_data(handle_, plane); }
const uint8_t *data(int plane) const
{
return fb_frame_get_data_const(handle_, plane);
}
void set_data(int plane, uint8_t *d)
{
fb_frame_set_data(handle_, plane, d);
}
int linesize(int plane) const
{
return fb_frame_get_linesize(handle_, plane);
}
void set_linesize(int plane, int l)
{
fb_frame_set_linesize(handle_, plane, l);
}
private:
FBFrame *handle_;
};
using AVFramePtr = std::shared_ptr<AVFrame>;
inline AVFramePtr create_av_frame_ptr(FBFrame *f)
{
return std::make_shared<AVFrame>(f);
}
inline AVFramePtr create_av_frame_ptr()
{
return std::make_shared<AVFrame>();
}
}
#endif // OAK_AVFRAMEPTR_H
-64
View File
@@ -1,64 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_CANCELABLEOBJECT_H
#define OAK_CANCELABLEOBJECT_H
#include "common/define.h"
#include "render/cancelatom.h"
namespace olive
{
class CancelableObject {
public:
CancelableObject()
{
}
void cancel()
{
cancel_.cancel();
CancelEvent();
}
CancelAtom *get_cancel_atom()
{
return &cancel_;
}
bool is_cancelled()
{
return cancel_.is_cancelled();
}
protected:
virtual void CancelEvent()
{
}
private:
CancelAtom cancel_;
};
}
#endif // OAK_CANCELABLEOBJECT_H
-179
View File
@@ -1,179 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "commandlineparser.h"
#include <QCoreApplication>
#include <QDebug>
CommandLineParser::~CommandLineParser()
{
foreach (const KnownOption &o, options_) {
delete o.option;
}
foreach (const KnownPositionalArgument &a, positional_args_) {
delete a.option;
}
}
const CommandLineParser::Option *
CommandLineParser::add_option(const QStringList &strings,
const QString &description, bool takes_arg,
const QString &arg_placeholder, bool hidden)
{
Option *o = new Option();
options_.append(
{ strings, description, o, takes_arg, arg_placeholder, hidden });
return o;
}
const CommandLineParser::PositionalArgument *
CommandLineParser::add_positional_argument(const QString &name,
const QString &description,
bool required)
{
PositionalArgument *a = new PositionalArgument();
positional_args_.append({ name, description, a, required });
return a;
}
void CommandLineParser::process(const QVector<QString> &argv)
{
int positional_index = 0;
for (int i = 1; i < argv.size(); i++) {
if (argv[i][0] == '-') {
// Must be an option
// Skip past first dashes
QString arg_basename = argv[i].mid(1);
bool matched_known = false;
for (int j = 0; j < options_.size(); j++) {
KnownOption &o = options_[j];
foreach (const QString &s, o.args) {
if (!s.compare(arg_basename, Qt::CaseInsensitive)) {
// Flag discovered!
o.option->set();
if (o.takes_arg && i + 1 < argv.size()) {
o.option->set_setting(argv[i + 1]);
i++;
}
matched_known = true;
goto found_flag;
}
}
}
found_flag:
if (!matched_known) {
qWarning() << "Unknown parameter:" << argv[i];
}
} else {
// Must be a positional flag
if (positional_index < positional_args_.size()) {
positional_args_[positional_index].option->set_setting(argv[i]);
positional_index++;
} else {
qWarning() << "Unknown parameter:" << argv[i];
}
}
}
}
void CommandLineParser::print_help(const char *filename)
{
printf("%s %s\n", QCoreApplication::applicationName().toUtf8().constData(),
QCoreApplication::applicationVersion().toUtf8().constData());
printf("Copyright (C) 2018-2022 Oak Video Editor Team\n");
QString positional_args;
for (int i = 0; i < positional_args_.size(); i++) {
if (i > 0) {
positional_args.append(' ');
}
positional_args.append('[');
positional_args.append(positional_args_.at(i).name);
positional_args.append(']');
}
const char *basename;
#ifdef Q_OS_WINDOWS
basename = strrchr(filename, '\\');
if (!basename) {
basename = strrchr(filename, '/');
}
#else
basename = strrchr(filename, '/');
#endif
if (basename) {
// Slash found, increment pointer to avoid showing the slash itself
basename++;
} else {
// If no slashes are found, assume string is already a basename
basename = filename;
}
printf("Usage: %s [options] %s\n\n", basename,
positional_args.toUtf8().constData());
foreach (const KnownOption &o, options_) {
if (o.hidden) {
continue;
}
QString all_args;
for (int i = 0; i < o.args.size(); i++) {
if (i > 0) {
all_args.append(QStringLiteral(", "));
}
const QString &this_arg = o.args.at(i);
all_args.append('-');
all_args.append(this_arg);
}
if (o.arg_placeholder.isEmpty()) {
printf(" %s\n", all_args.toUtf8().constData());
} else {
printf(" %s <%s>\n", all_args.toUtf8().constData(),
o.arg_placeholder.toUtf8().constData());
}
printf(" %s\n\n", o.description.toUtf8().constData());
}
printf("\n");
}
-122
View File
@@ -1,122 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_COMMANDLINEPARSER_H
#define OAK_COMMANDLINEPARSER_H
#include <QStringList>
#include <QVector>
#include "common/define.h"
/**
* @brief Command-line argument parser
*
* You may be wondering why we don't use QCommandLineParser instead of a custom implementation like
* this. The reason why is because QCommandLineParser requires a QApplication object of some kind
* to already have been created before it can parse anything, but we need to be able to control
* whether a QApplication (GUI-mode) or a QCoreApplication (CLI-mode) is created which is set by
* the user as a command line argument. Therefore we needed a custom implementation that could
* parse arguments without the need for a Q(Core)Application to be present already.
*/
class CommandLineParser {
public:
~CommandLineParser();
DISABLE_COPY_MOVE(CommandLineParser)
class PositionalArgument {
public:
PositionalArgument() = default;
const QString &get_setting() const
{
return setting_;
}
void set_setting(const QString &s)
{
setting_ = s;
}
private:
QString setting_;
};
class Option : public PositionalArgument {
public:
Option()
{
is_set_ = false;
}
bool is_set() const
{
return is_set_;
}
void set()
{
is_set_ = true;
}
private:
bool is_set_;
};
CommandLineParser() = default;
const Option *add_option(const QStringList &strings,
const QString &description, bool takes_arg = false,
const QString &arg_placeholder = QString(),
bool hidden = false);
const PositionalArgument *add_positional_argument(const QString &name,
const QString &description,
bool required = false);
void process(const QVector<QString> &argv);
void print_help(const char *filename);
private:
struct KnownOption {
QStringList args;
QString description;
Option *option;
bool takes_arg;
QString arg_placeholder;
bool hidden;
};
struct KnownPositionalArgument {
QString name;
QString description;
PositionalArgument *option;
bool required;
};
QVector<KnownOption> options_;
QVector<KnownPositionalArgument> positional_args_;
};
#endif // OAK_COMMANDLINEPARSER_H
-102
View File
@@ -1,102 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "crashpadinterface.h"
#ifdef USE_CRASHPAD
#include <QCoreApplication>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QProcess>
#include "crashpadutils.h"
#include "filefunctions.h"
#if BUILDFLAG(IS_WIN)
#include <Windows.h>
#endif
crashpad::CrashpadClient *client;
bool InitializeCrashpad()
{
QString report_path = QDir(olive::FileFunctions::GetTempFilePath())
.filePath(QStringLiteral("reports"));
QString handler_fn =
olive::FileFunctions::GetFormattedExecutableForPlatform(
QStringLiteral("crashpad_handler"));
// Generate absolute path
QString handler_abs_path =
QDir(QCoreApplication::applicationDirPath()).filePath(handler_fn);
bool status = false;
if (QFileInfo::exists(handler_abs_path)) {
base::FilePath handler(QSTRING_TO_BASE_STRING(handler_abs_path));
base::FilePath reports_dir(QSTRING_TO_BASE_STRING(report_path));
base::FilePath metrics_dir(
QSTRING_TO_BASE_STRING(QDir(olive::FileFunctions::GetTempFilePath())
.filePath(QStringLiteral("metrics"))));
// Metadata that will be posted to the server with the crash report map
std::map<std::string, std::string> annotations;
// Disable crashpad rate limiting so that all crashes have dmp files
std::vector<std::string> arguments;
arguments.push_back("--no-rate-limit");
arguments.push_back("--no-upload-gzip");
// Initialize Crashpad database
std::unique_ptr<crashpad::CrashReportDatabase> database =
crashpad::CrashReportDatabase::Initialize(reports_dir);
if (database == NULL)
return false;
// Disable automated crash uploads
crashpad::Settings *settings = database->GetSettings();
if (settings == NULL)
return false;
settings->SetUploadsEnabled(false);
// Start crash handler
client = new crashpad::CrashpadClient();
status = client->StartHandler(
handler, reports_dir, metrics_dir,
"https://olivevideoeditor.org/crashpad/report.php", annotations,
arguments, true, true);
}
// Override Crashpad exception filter with our own
if (!status) {
qWarning()
<< "Failed to start Crashpad, automatic crash reporting will be disabled";
}
return status;
}
#endif // USE_CRASHPAD
-33
View File
@@ -1,33 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_CRASHPAD_INTERFACE_H
#define OAK_CRASHPAD_INTERFACE_H
#ifdef USE_CRASHPAD
#include <client/crash_report_database.h>
#include <client/settings.h>
bool InitializeCrashpad();
#endif // USE_CRASHPAD
#endif // OAK_CRASHPAD_INTERFACE_H
-41
View File
@@ -1,41 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_CRASHPADUTILS_H
#define OAK_CRASHPADUTILS_H
#include <client/crashpad_client.h>
// Copied from base::FilePath to match its macro
#if BUILDFLAG(IS_POSIX)
// On most platforms, native pathnames are char arrays, and the encoding
// may or may not be specified. On Mac OS X, native pathnames are encoded
// in UTF-8.
#define QSTRING_TO_BASE_STRING(x) x.toStdString()
#define BASE_STRING_TO_QSTRING(x) QString::fromStdString(x)
#elif BUILDFLAG(IS_WIN)
// On Windows, for Unicode-aware applications, native pathnames are wchar_t
// arrays encoded in UTF-16.
#define QSTRING_TO_BASE_STRING(x) x.toStdWString()
#define BASE_STRING_TO_QSTRING(x) QString::fromStdWString(x)
#endif // BUILDFLAG(IS_WIN)
#endif // OAK_CRASHPADUTILS_H
-22
View File
@@ -1,22 +0,0 @@
/*
* Oak Video Editor - Non-Linear Video Editor
* Copyright (C) 2025 Olive CE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "current.h"
Current Current::current;
-90
View File
@@ -1,90 +0,0 @@
/*
* Oak Video Editor - Non-Linear Video Editor
* Copyright (C) 2025 Olive CE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef OAK_CURRENT_H
#define OAK_CURRENT_H
#include "pluginSupport/olivehost.h"
#include "render/videoparams.h"
#include "render/job/pluginjob.h"
class Current {
public:
static Current &getInstance()
{
return current;
}
olive::VideoParams &current_video_params()
{
return currentVideoParams_;
}
olive::AudioParams &current_audio_params()
{
return currentAudioParams_;
}
void setCurrentVideoParams(olive::VideoParams &params)
{
currentVideoParams_ = params;
}
void setCurrentAudioParams(olive::AudioParams &params)
{
currentAudioParams_ = params;
}
void setCurrentVideoParams(olive::VideoParams &&params)
{
currentVideoParams_ = params;
}
void setCurrentAudioParams(olive::AudioParams &&params)
{
currentAudioParams_ = params;
}
bool interactive()
{
return true;
}
std::shared_ptr<olive::plugin::OliveHost> plugin_host()
{
return myHost_;
}
void setPluginHost(std::shared_ptr<olive::plugin::OliveHost> host)
{
myHost_ = host;
}
std::shared_ptr<OFX::Host::ImageEffect::PluginCache> plugin_cache()
{
return plugin_cache_;
}
void
setPluginCache(std::shared_ptr<OFX::Host::ImageEffect::PluginCache> cache)
{
plugin_cache_ = cache;
}
private:
static Current current;
olive::VideoParams currentVideoParams_;
olive::AudioParams currentAudioParams_;
std::shared_ptr<olive::plugin::OliveHost> myHost_;
std::shared_ptr<OFX::Host::ImageEffect::PluginCache> plugin_cache_;
};
#endif //OAK_CURRENT_H
-61
View File
@@ -1,61 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "debug.h"
namespace olive
{
void debug_handler(QtMsgType type, const QMessageLogContext &context,
const QString &msg)
{
QByteArray local_msg = msg.toLocal8Bit();
const char *msg_type = "UNKNOWN";
switch (type) {
case QtDebugMsg:
msg_type = "DEBUG";
break;
case QtInfoMsg:
msg_type = "INFO";
break;
case QtWarningMsg:
msg_type = "WARNING";
break;
case QtCriticalMsg:
msg_type = "ERROR";
break;
case QtFatalMsg:
msg_type = "FATAL";
break;
}
//fprintf(stderr, "[%s] %s (%s:%u)\n", msg_type, localMsg.constData(), context.function, context.line);
fprintf(stderr, "[%s] %s\n", msg_type, local_msg.constData());
#ifdef Q_OS_WINDOWS
// Windows still seems to buffer stderr and we want to see debug messages immediately, so here we make sure each line
// is flushed
fflush(stderr);
#endif
}
}
-37
View File
@@ -1,37 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_DEBUG_H
#define OAK_DEBUG_H
#include <QDebug>
#include "common/define.h"
namespace olive
{
void debug_handler(QtMsgType type, const QMessageLogContext &context,
const QString &msg);
}
#endif // OAK_DEBUG_H
-104
View File
@@ -1,104 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_DECIBEL_H
#define OAK_DECIBEL_H
#include <QtGlobal>
#include <cmath>
//#define ALLOW_RETURNING_INFINITY
namespace olive
{
class Decibel {
public:
// In basically all circumstances, this should calculate to 0.0 linear
static constexpr double minimum = -200.0;
static double from_linear(double linear)
{
double v = double(20.0) * std::log10(linear);
#ifndef ALLOW_RETURNING_INFINITY
if (std::isinf(v)) {
return minimum;
}
#endif
return v;
}
static double to_linear(double decibel)
{
double to_linear = std::pow(double(10.0), decibel / double(20.0));
// Minimum threshold that we figure is close enough to 0 that we may as well just return 0
if (to_linear < 0.000001) {
return 0;
} else {
return to_linear;
}
}
static double from_logarithmic(double logarithmic)
{
if (logarithmic < 0.001)
#ifdef ALLOW_RETURNING_INFINITY
return std::numeric_limits<double>::infinity();
#else
return minimum;
#endif
else if (logarithmic > 0.99)
return 0;
else
return 20.0 * std::log10(-std::log(1 - logarithmic) / lo_g100);
}
static double to_logarithmic(double decibel)
{
if (qFuzzyIsNull(decibel)) {
return 1;
} else {
return 1 - std::exp(-std::pow(10.0, decibel / 20.0) * lo_g100);
}
}
static double linear_to_logarithmic(double linear)
{
return 1 - std::exp(-linear * lo_g100);
}
static double logarithmic_to_linear(double logarithmic)
{
if (logarithmic > 0.99) {
return 1;
} else {
return -std::log(1 - logarithmic) / lo_g100;
}
}
private:
static constexpr double lo_g100 = 4.60517018599;
};
}
#endif // OAK_DECIBEL_H
-68
View File
@@ -1,68 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_OLIVECOMMONDEFINE_H
#define OAK_OLIVECOMMONDEFINE_H
namespace olive
{
/// The minimum size an icon in ProjectExplorer can be
const int k_project_icon_size_minimum = 16;
/// The maximum size an icon in ProjectExplorer can be
const int k_project_icon_size_maximum = 256;
/// The default size an icon in ProjectExplorer can be
const int k_project_icon_size_default = 64;
const int k_bytes_in_gigabyte = 1073741824;
}
#define MACRO_NAME_AS_STR(s) #s
#define MACRO_VAL_AS_STR(s) MACRO_NAME_AS_STR(s)
#define OLIVE_NS_CONST_ARG(x, y) \
QArgument<const olive::x>("const " MACRO_VAL_AS_STR(olive) "::" #x, y)
#define OLIVE_NS_ARG(x, y) \
QArgument<olive::x>(MACRO_VAL_AS_STR(olive) "::" #x, y)
#define OLIVE_NS_RETURN_ARG(x, y) \
QReturnArgument<olive::x>(MACRO_VAL_AS_STR(olive) "::" #x, y)
/**
* Copy/move deleters. Similar to Q_DISABLE_COPY_MOVE, et al. but those functions are not present in Qt < 5.13 so we
* use our own functions for portability.
*/
#define DISABLE_COPY(Class) \
Class(const Class &) = delete; \
Class &operator=(const Class &) = delete;
#define DISABLE_MOVE(Class) \
Class(Class &&) = delete; \
Class &operator=(Class &&) = delete;
#define DISABLE_COPY_MOVE(Class) \
DISABLE_COPY(Class) \
DISABLE_MOVE(Class)
#endif // OAK_OLIVECOMMONDEFINE_H
-47
View File
@@ -1,47 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_DIGIT_H
#define OAK_DIGIT_H
#include <stdint.h>
namespace olive
{
inline int64_t get_digit_count(int64_t input)
{
input = std::abs(input);
int64_t lim = 10;
int64_t digit = 1;
while (input >= lim) {
lim *= 10;
digit++;
}
return digit;
}
}
#endif // OAK_DIGIT_H
-43
View File
@@ -1,43 +0,0 @@
/***
Oak - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_DROPWORKFLOWBEHAVIOR_H
#define OAK_DROPWORKFLOWBEHAVIOR_H
namespace olive
{
/**
* @brief Behavior when media is dropped onto a timeline without a sequence
*
* Shared by the config defaults (engine layer) and the timeline import
* tool (UI layer). Enumerator order matches the previous
* ImportTool::DropWithoutSequenceBehavior.
*/
enum DropWithoutSequenceBehavior {
k_dws_ask,
k_dws_auto,
k_dws_manual,
k_dws_disable
};
}
#endif // OAK_DROPWORKFLOWBEHAVIOR_H
-197
View File
@@ -1,197 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "common/ffmpegutils.h"
namespace olive
{
int FFmpegUtils::get_compatible_bridge_pixel_format(int pix_fmt,
PixelFormat maximum)
{
int possible_pix_fmts[4];
possible_pix_fmts[0] = fb_pix_fmt_rgba;
if (maximum == PixelFormat::u8) {
possible_pix_fmts[1] = fb_pix_fmt_none;
} else {
possible_pix_fmts[1] = fb_pix_fmt_rgb_a64_le;
if (maximum == PixelFormat::f32) {
possible_pix_fmts[2] = fb_pix_fmt_rgba_f32_le;
possible_pix_fmts[3] = fb_pix_fmt_none;
} else {
possible_pix_fmts[2] = fb_pix_fmt_none;
}
}
return fb_find_best_pix_fmt_of_list(possible_pix_fmts, pix_fmt);
}
SampleFormat FFmpegUtils::get_native_sample_format(int smp_fmt)
{
switch (smp_fmt) {
case fb_sample_fmt_u8:
return SampleFormat::u8;
case fb_sample_fmt_s16:
return SampleFormat::s16;
case fb_sample_fmt_s32:
return SampleFormat::s32;
case fb_sample_fmt_s64:
return SampleFormat::s64;
case fb_sample_fmt_flt:
return SampleFormat::f32;
case fb_sample_fmt_dbl:
return SampleFormat::f64;
case fb_sample_fmt_u8_p:
return SampleFormat::u8_p;
case fb_sample_fmt_s16_p:
return SampleFormat::s16_p;
case fb_sample_fmt_s32_p:
return SampleFormat::s32_p;
case fb_sample_fmt_s64_p:
return SampleFormat::s64_p;
case fb_sample_fmt_fltp:
return SampleFormat::f32_p;
case fb_sample_fmt_dblp:
return SampleFormat::f64_p;
default:
break;
}
return SampleFormat::invalid;
}
int FFmpegUtils::get_f_fmpeg_sample_format(const SampleFormat &smp_fmt)
{
switch (smp_fmt) {
case SampleFormat::u8:
return fb_sample_fmt_u8;
case SampleFormat::s16:
return fb_sample_fmt_s16;
case SampleFormat::s32:
return fb_sample_fmt_s32;
case SampleFormat::s64:
return fb_sample_fmt_s64;
case SampleFormat::f32:
return fb_sample_fmt_flt;
case SampleFormat::f64:
return fb_sample_fmt_dbl;
case SampleFormat::u8_p:
return fb_sample_fmt_u8_p;
case SampleFormat::s16_p:
return fb_sample_fmt_s16_p;
case SampleFormat::s32_p:
return fb_sample_fmt_s32_p;
case SampleFormat::s64_p:
return fb_sample_fmt_s64_p;
case SampleFormat::f32_p:
return fb_sample_fmt_fltp;
case SampleFormat::f64_p:
return fb_sample_fmt_dblp;
case SampleFormat::invalid:
case SampleFormat::count:
break;
}
return fb_sample_fmt_none;
}
int FFmpegUtils::convert_jpeg_space_to_regular_space(int f)
{
switch (f) {
case fb_pix_fmt_yuv_j420_p:
return fb_pix_fmt_yu_v420_p;
case fb_pix_fmt_yuv_j422_p:
return fb_pix_fmt_yu_v422_p;
case fb_pix_fmt_yuv_j444_p:
return fb_pix_fmt_yu_v444_p;
case fb_pix_fmt_yuv_j440_p:
return fb_pix_fmt_yu_v440_p;
case fb_pix_fmt_yuv_j411_p:
return fb_pix_fmt_yu_v411_p;
default:
break;
}
return f;
}
int FFmpegUtils::get_f_fmpeg_pixel_format(const PixelFormat &pix_fmt,
int channel_layout)
{
if (channel_layout == VideoParams::k_rgb_channel_count) {
switch (pix_fmt) {
case PixelFormat::u8:
return fb_pix_fmt_rg_b24;
case PixelFormat::u10:
return fb_pix_fmt_none;
case PixelFormat::u16:
return fb_pix_fmt_rg_b48_le;
case PixelFormat::f16:
return fb_pix_fmt_rgb_f16_le;
case PixelFormat::f32:
return fb_pix_fmt_rgb_f32_le;
case PixelFormat::invalid:
case PixelFormat::count:
break;
}
} else if (channel_layout == VideoParams::k_rgba_channel_count) {
switch (pix_fmt) {
case PixelFormat::u8:
return fb_pix_fmt_rgba;
case PixelFormat::u10:
return fb_pix_fmt_none;
case PixelFormat::u16:
return fb_pix_fmt_rgb_a64_le;
case PixelFormat::f16:
return fb_pix_fmt_rgba_f16_le;
case PixelFormat::f32:
return fb_pix_fmt_rgba_f32_le;
case PixelFormat::invalid:
case PixelFormat::count:
break;
}
}
return fb_pix_fmt_none;
}
PixelFormat FFmpegUtils::get_compatible_pixel_format(const PixelFormat &pix_fmt)
{
switch (pix_fmt) {
case PixelFormat::u8:
return PixelFormat::u8;
case PixelFormat::u10:
return PixelFormat::u8;
case PixelFormat::u16:
case PixelFormat::f16:
case PixelFormat::f32:
return PixelFormat::u16;
case PixelFormat::invalid:
case PixelFormat::count:
break;
}
return PixelFormat::invalid;
}
}
-89
View File
@@ -1,89 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_FFMPEGABSTRACTION_H
#define OAK_FFMPEGABSTRACTION_H
#include <ffmpeg_bridge/ffmpeg_bridge.h>
#include <olive/core/core.h>
#include "render/videoparams.h"
namespace olive
{
using namespace core;
/**
* @brief C++ adapter mapping Olive's native enums to bridge pixel/sample
* formats
*
* All "FFmpeg" formats here are actually the opaque FBPixelFormat /
* FBSampleFormat constants of the ffmpeg_bridge library; no FFmpeg header
* or structure is ever seen by the editor.
*/
class FFmpegUtils {
public:
/**
* @brief Returns a bridge pixel format that can be used to convert a frame to a data type Olive supports with minimal data loss
*
* Named distinctly from the native PixelFormat overload below: with both
* taking a single argument, an unscoped enum argument would silently
* prefer an int overload over the PixelFormat one.
*/
static int get_compatible_bridge_pixel_format(
int pix_fmt, PixelFormat maximum = PixelFormat::invalid);
/**
* @brief Returns a native pixel format that can be used to convert from a native frame to a bridge frame with minimal data loss
*/
static PixelFormat get_compatible_pixel_format(const PixelFormat &pix_fmt);
/**
* @brief Returns a bridge pixel format for a given native pixel format
*/
static int get_f_fmpeg_pixel_format(const PixelFormat &pix_fmt,
int channel_layout);
/**
* @brief Returns a native sample format type for a given bridge sample format
*/
static SampleFormat get_native_sample_format(int smp_fmt);
/**
* @brief Returns a bridge sample format type for a given native type
*/
static int get_f_fmpeg_sample_format(const SampleFormat &smp_fmt);
/**
* @brief Convert "JPEG"/full-range colorspace to its regular counterpart
*
* "JPEG "spaces are deprecated in favor of the regular space and setting `color_range`. For the
* time being, FFmpeg still uses these JPEG spaces, so for simplicity (since we *are* color_range
* aware), we use this function.
*/
static int convert_jpeg_space_to_regular_space(int f);
};
}
#endif // OAK_FFMPEGABSTRACTION_H
-253
View File
@@ -1,253 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "filefunctions.h"
#include <QCoreApplication>
#include <QCryptographicHash>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QStandardPaths>
#include "config/config.h"
namespace olive
{
QString FileFunctions::get_unique_file_identifier(const QString &filename)
{
QFileInfo info(filename);
if (!info.exists()) {
return QString();
}
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(info.absoluteFilePath().toUtf8());
hash.addData(
QString::number(info.lastModified().toMSecsSinceEpoch()).toUtf8());
QByteArray result = hash.result();
return QString(result.toHex());
}
QString FileFunctions::get_configuration_location()
{
if (is_portable()) {
return get_application_path();
} else {
QString s =
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir(s).mkpath(".");
return s;
}
}
bool FileFunctions::is_portable()
{
return QFileInfo::exists(QDir(get_application_path()).filePath("portable"));
}
QString FileFunctions::get_application_path()
{
return QCoreApplication::applicationDirPath();
}
QString FileFunctions::get_temp_file_path()
{
QString temp_path =
QDir(
QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation))
.filePath(QCoreApplication::organizationName()))
.filePath(QCoreApplication::applicationName());
// Ensure it exists
QDir(temp_path).mkpath(".");
return temp_path;
}
bool FileFunctions::can_copy_directory_without_overwriting(const QString &source,
const QString &dest)
{
QFileInfoList info_list = QDir(source).entryInfoList();
foreach (const QFileInfo &info, info_list) {
// QDir::NoDotAndDotDot continues to not work, so we have to check manually
if (info.fileName() == QStringLiteral(".") ||
info.fileName() == QStringLiteral("..")) {
continue;
}
QString dest_equivalent = QDir(dest).filePath(info.fileName());
if (info.isDir()) {
if (!can_copy_directory_without_overwriting(info.absoluteFilePath(),
dest_equivalent)) {
return false;
}
} else if (QFileInfo::exists(dest_equivalent)) {
return false;
}
}
return true;
}
void FileFunctions::copy_directory(const QString &source, const QString &dest,
bool overwrite)
{
QDir d(source);
if (!d.exists()) {
qCritical()
<< "Failed to copy directory, source" << source << "didn't exist";
return;
}
QDir dest_dir(dest);
if (!dest_dir.mkpath(QStringLiteral("."))) {
qCritical() << "Failed to create destination directory" << dest;
return;
}
QFileInfoList l = d.entryInfoList();
foreach (const QFileInfo &info, l) {
// QDir::NoDotAndDotDot continues to not work, so we have to check manually
if (info.fileName() == QStringLiteral(".") ||
info.fileName() == QStringLiteral("..")) {
continue;
}
QString dest_file_path = dest_dir.filePath(info.fileName());
if (info.isDir()) {
// Copy dir
copy_directory(info.absoluteFilePath(), dest_file_path, overwrite);
} else {
// Copy file
if (overwrite && QFile::exists(dest_file_path)) {
QFile file(dest_file_path);
file.setPermissions(
file.permissions() | QFileDevice::WriteOwner |
QFileDevice::WriteUser | QFileDevice::WriteGroup |
QFileDevice::WriteOther);
file.remove();
}
QFile::copy(info.absoluteFilePath(), dest_file_path);
}
}
}
bool FileFunctions::directory_is_valid(const QDir &d,
bool try_to_create_if_not_exists)
{
// Return whether the directory exists, or whether it could be created if it doesn't
return d.exists() ||
(try_to_create_if_not_exists && d.mkpath(QStringLiteral(".")));
}
QString FileFunctions::ensure_filename_extension(QString fn,
const QString &extension)
{
// No-op if either input is empty
if (!fn.isEmpty() && !extension.isEmpty()) {
QString extension_with_dot;
extension_with_dot.append('.');
extension_with_dot.append(extension);
if (!fn.endsWith(extension_with_dot, Qt::CaseInsensitive)) {
fn.append(extension_with_dot);
}
}
return fn;
}
QString FileFunctions::read_file_as_string(const QString &filename)
{
QFile f(filename);
QString file_data;
if (f.open(QFile::ReadOnly | QFile::Text)) {
QTextStream text_stream(&f);
file_data = text_stream.readAll();
f.close();
}
return file_data;
}
QString FileFunctions::get_safe_temporary_filename(const QString &original)
{
int counter = 0;
QFileInfo original_info(original);
QString basename = original_info.baseName();
QString complete_suffix = original_info.completeSuffix();
// If we have a complete suffix, make sure there's a period in it
if (!complete_suffix.isEmpty()) {
complete_suffix.prepend('.');
}
QString temp_abs_path;
do {
temp_abs_path = original_info.dir().filePath(
QStringLiteral("%1.tmp%2%3")
.arg(basename, QString::number(counter), complete_suffix));
counter++;
} while (QFileInfo::exists(temp_abs_path));
return temp_abs_path;
}
bool FileFunctions::rename_file_allow_overwrite(const QString &from,
const QString &to)
{
if (QFileInfo::exists(to) && !QFile::remove(to)) {
qCritical() << "Couldn't remove existing file" << to << "for overwrite";
return false;
}
// By this point, we can assume `to` either never existed or has now been deleted
if (!QFile::rename(from, to)) {
qCritical() << "Failed to rename file" << from << "to" << to;
return false;
}
return true;
}
QString FileFunctions::get_auto_recovery_root()
{
return QDir(QStandardPaths::writableLocation(
QStandardPaths::AppLocalDataLocation))
.filePath(QStringLiteral("autorecovery"));
}
}
-109
View File
@@ -1,109 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_FILEFUNCTIONS_H
#define OAK_FILEFUNCTIONS_H
#include <QDir>
#include <QString>
#include "common/define.h"
namespace olive
{
/**
* @brief A collection of static file and directory functions
*/
class FileFunctions {
public:
/**
* @brief Returns true if the application is running in portable mode
*
* In portable mode, any persistent configuration files should be made in a path relative to the application rather
* than in the user's home folder.
*/
static bool is_portable();
static QString get_unique_file_identifier(const QString &filename);
static QString get_configuration_location();
static QString get_application_path();
static QString get_temp_file_path();
static bool can_copy_directory_without_overwriting(const QString &source,
const QString &dest);
static void copy_directory(const QString &source, const QString &dest,
bool overwrite = false);
static bool directory_is_valid(const QDir &dir,
bool try_to_create_if_not_exists = true);
/**
* @brief Ensures a given filename has a certain extension
*
* Checks if the filename has the extension provided and appends it if not. The extension is
* checked case-insensitive. The extension should be provided with no dot (e.g. "ove" rather than
* ".ove").
* @return The filename provided either untouched or with the extension appended to it.
*/
static QString ensure_filename_extension(QString fn,
const QString &extension);
static QString read_file_as_string(const QString &filename);
/**
* @brief Returns a temporary filename that can be used while writing rather than the original
*
* If overwriting a file, it's safest to write to a new file first and then only replace it at
* the end so that if the program crashes or the user cancels the save half way through, the
* original file is still intact.
*
* This function returns a slight variant of the filename provided that's guaranteed to not exist
* and therefore won't overwrite anything important.
*/
static QString get_safe_temporary_filename(const QString &original);
/**
* @brief Renames a file from `from` to `to`, deleting `to` if such a file already exists first
*/
static bool rename_file_allow_overwrite(const QString &from,
const QString &to);
inline static QString get_formatted_executable_for_platform(QString unformatted)
{
#ifdef Q_OS_WINDOWS
unformatted.append(QStringLiteral(".exe"));
#endif
return unformatted;
}
static QString get_auto_recovery_root();
};
}
#endif // OAK_FILEFUNCTIONS_H
-494
View File
@@ -1,494 +0,0 @@
/*
* Oak Video Editor - Non-Linear Video Editor
* Copyright (C) 2025 Olive CE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "html.h"
#include <QDebug>
#include <QTextBlock>
#include "xmlutils.h"
namespace olive
{
const QVector<QString> Html::k_block_tags = { QStringLiteral("p"),
QStringLiteral("div") };
inline bool str_equals(const QStringView &a, const QStringView &b)
{
return !a.compare(b, Qt::CaseInsensitive);
}
QString Html::doc_to_html(const QTextDocument *doc)
{
QString html;
QXmlStreamWriter writer(&html);
//writer.setAutoFormatting(true);
for (auto it = doc->begin(); it != doc->end(); it = it.next()) {
write_block(&writer, it);
}
return html;
}
struct HtmlNode {
QString tag;
QTextCharFormat format;
};
QTextCharFormat merge_html_formats(const QVector<HtmlNode> &stack)
{
QTextCharFormat f;
for (int i = 0; i < stack.size(); i++) {
f.merge(stack.at(i).format);
}
return f;
}
void Html::html_to_doc(QTextDocument *doc, const QString &html)
{
// Empty doc
doc->clear();
bool inside_block = true;
// Create cursor, which appears to be Qt's official way of inserting blocks and fragments
QTextCursor c(doc);
QString wrapped = QStringLiteral("<html>").append(html).append("</html>");
QXmlStreamReader reader(wrapped);
QVector<HtmlNode> fmt_stack;
QTextCharFormat default_fmt;
default_fmt.setFontWeight(QFont::Normal);
fmt_stack.append({ QStringLiteral("html"), default_fmt });
QTextCharFormat current_fmt;
while (!reader.atEnd()) {
reader.readNext();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
QString tag = reader.name().toString().toLower();
fmt_stack.append({ tag, read_char_format(reader.attributes()) });
current_fmt = merge_html_formats(fmt_stack);
if (k_block_tags.contains(tag)) {
QTextBlockFormat block_fmt =
read_block_format(reader.attributes());
if (inside_block) {
c.setBlockFormat(block_fmt);
c.setBlockCharFormat(current_fmt);
} else {
c.insertBlock(block_fmt, current_fmt);
inside_block = true;
}
}
} else if (reader.tokenType() == QXmlStreamReader::Characters) {
QString characters = reader.text().toString();
c.insertText(characters, current_fmt);
} else if (reader.tokenType() == QXmlStreamReader::EndElement) {
QString tag = reader.name().toString().toLower();
for (int i = fmt_stack.size() - 1; i >= 0; i--) {
if (fmt_stack.at(i).tag == tag) {
fmt_stack.removeAt(i);
current_fmt = merge_html_formats(fmt_stack);
if (k_block_tags.contains(tag)) {
inside_block = false;
}
break;
}
}
}
}
if (reader.error()) {
qCritical() << "Failed to parse HTML:" << reader.errorString();
}
}
void Html::write_block(QXmlStreamWriter *writer, const QTextBlock &block)
{
writer->writeStartElement(QStringLiteral("p"));
const QTextBlockFormat &fmt = block.blockFormat();
// Write block alignment
if (!(fmt.alignment() & Qt::AlignLeft)) {
if (fmt.alignment() & Qt::AlignRight) {
writer->writeAttribute(QStringLiteral("align"),
QStringLiteral("right"));
} else if (fmt.alignment() & Qt::AlignHCenter) {
writer->writeAttribute(QStringLiteral("align"),
QStringLiteral("center"));
} else if (fmt.alignment() & Qt::AlignJustify) {
writer->writeAttribute(QStringLiteral("align"),
QStringLiteral("justify"));
}
}
// RTL support
if (block.textDirection() == Qt::RightToLeft) {
writer->writeAttribute(QStringLiteral("dir"), QStringLiteral("rtl"));
}
// Write CSS attributes
QString style;
if (fmt.lineHeightType() != QTextBlockFormat::SingleHeight) {
write_css_property(&style, QStringLiteral("line-height"),
QStringLiteral("%1%").arg(fmt.lineHeight()));
}
write_char_format(&style, block.charFormat());
if (!style.isEmpty()) {
writer->writeAttribute(QStringLiteral("style"), style);
}
auto it = block.begin();
if (it != block.end()) {
for (; it != block.end(); it++) {
write_fragment(writer, it.fragment());
}
}
writer->writeEndElement(); // p
}
void Html::write_fragment(QXmlStreamWriter *writer,
const QTextFragment &fragment)
{
const QTextCharFormat &fmt = fragment.charFormat();
writer->writeStartElement(QStringLiteral("span"));
// Write CSS attributes
QString style;
write_char_format(&style, fmt);
if (!style.isEmpty()) {
writer->writeAttribute(QStringLiteral("style"), style);
}
QStringList lines = fragment.text().split(QChar::LineSeparator);
bool first_line = true;
foreach (const QString &l, lines) {
if (first_line) {
first_line = false;
} else {
writer->writeEmptyElement(QStringLiteral("br"));
}
writer->writeCharacters(l);
}
writer->writeEndElement(); // span
}
void Html::write_css_property(QString *style, const QString &key,
const QStringList &values)
{
QString value;
foreach (QString v, values) {
if (v.contains(' ')) {
v = QStringLiteral("'%1'").arg(v);
}
append_string_auto_space(&value, v);
}
append_string_auto_space(style, QStringLiteral("%1: %2;").arg(key, value));
}
void Html::write_char_format(QString *style, const QTextCharFormat &fmt)
{
QStringList families = fmt.fontFamilies().toStringList();
if (!families.isEmpty()) {
write_css_property(style, QStringLiteral("font-family"),
families.first());
}
if (fmt.hasProperty(QTextFormat::FontPointSize)) {
write_css_property(
style, QStringLiteral("font-size"),
QStringLiteral("%1pt").arg(QString::number(fmt.fontPointSize())));
}
if (fmt.hasProperty(QTextFormat::FontWeight)) {
write_css_property(style, QStringLiteral("font-weight"),
QString::number(fmt.fontWeight() * 8));
}
if (fmt.hasProperty(QTextFormat::FontItalic)) {
write_css_property(style, QStringLiteral("font-style"),
fmt.fontItalic() ? QStringLiteral("italic") :
QStringLiteral("normal"));
}
if (fmt.hasProperty(QTextFormat::FontStyleName)) {
write_css_property(style, QStringLiteral("-ove-font-style"),
fmt.fontStyleName().toString());
}
QStringList deco;
if (fmt.fontUnderline()) {
deco.append(QStringLiteral("underline"));
}
if (fmt.fontStrikeOut()) {
deco.append(QStringLiteral("line-through"));
}
if (fmt.fontOverline()) {
deco.append(QStringLiteral("overline"));
}
if (!deco.isEmpty()) {
write_css_property(style, QStringLiteral("text-decoration"), deco);
}
if (fmt.foreground().style() != Qt::NoBrush) {
const QColor &color = fmt.foreground().color();
QString cs;
if (color.alpha() == 255) {
cs = color.name();
} else if (color.alpha()) {
cs = QStringLiteral("rgba(%1, %2, %3, %4)")
.arg(QString::number(color.red()),
QString::number(color.green()),
QString::number(color.blue()),
QString::number(color.alphaF()));
}
write_css_property(style, QStringLiteral("color"), cs);
}
if (fmt.fontCapitalization() != QFont::MixedCase) {
if (fmt.fontCapitalization() == QFont::SmallCaps) {
write_css_property(style, QStringLiteral("font-variant"),
QStringLiteral("small-caps"));
// TODO: Add others
}
}
if (fmt.fontLetterSpacing() != 0.0) {
write_css_property(style, QStringLiteral("letter-spacing"),
QStringLiteral("%1%").arg(
QString::number(fmt.fontLetterSpacing())));
}
if (fmt.fontStretch() != 0) {
write_css_property(
style, QStringLiteral("font-stretch"),
QStringLiteral("%1%").arg(QString::number(fmt.fontStretch())));
}
}
QTextCharFormat Html::read_char_format(const QXmlStreamAttributes &attributes)
{
QTextCharFormat fmt;
foreach (const QXmlStreamAttribute &attr, attributes) {
if (str_equals(attr.name(), QStringLiteral("style"))) {
auto css = get_css_from_style(attr.value().toString());
for (auto it = css.begin(); it != css.end(); it++) {
const QString &first_val = it.value().first();
if (it.key() == QStringLiteral("font-family")) {
fmt.setFontFamilies({ first_val });
} else if (it.key() == QStringLiteral("font-size")) {
if (first_val.endsWith(QStringLiteral("pt"),
Qt::CaseInsensitive)) {
fmt.setFontPointSize(first_val.chopped(2).toDouble());
}
} else if (it.key() == QStringLiteral("font-weight")) {
fmt.setFontWeight(first_val.toInt() / 8);
} else if (it.key() == QStringLiteral("font-style")) {
fmt.setFontItalic(
str_equals(first_val, QStringLiteral("italic")));
} else if (it.key() == QStringLiteral("text-decoration")) {
foreach (const QString &v, it.value()) {
if (str_equals(v, QStringLiteral("underline"))) {
fmt.setFontUnderline(true);
} else if (str_equals(v,
QStringLiteral("line-through"))) {
fmt.setFontStrikeOut(true);
} else if (str_equals(v, QStringLiteral("overline"))) {
fmt.setFontOverline(true);
}
}
} else if (it.key() == QStringLiteral("color")) {
if (first_val.startsWith(QStringLiteral("rgba"),
Qt::CaseInsensitive)) {
QString vals_only = first_val;
vals_only.remove(QStringLiteral("rgba"));
vals_only.remove(QStringLiteral("("));
vals_only.remove(QStringLiteral(")"));
QStringList rgba = vals_only.split(',');
if (rgba.size() == 4) {
QColor c;
c.setRed(rgba.at(0).toInt()); // Writer emits 0-255 RGB (CSS rgba() convention)
c.setGreen(rgba.at(1).toInt());
c.setBlue(rgba.at(2).toInt());
c.setAlphaF(rgba.at(3).toDouble());
fmt.setForeground(c);
}
} else {
fmt.setForeground(QColor(first_val));
}
} else if (it.key() == QStringLiteral("font-variant")) {
if (str_equals(first_val, QStringLiteral("small-caps"))) {
fmt.setFontCapitalization(QFont::SmallCaps);
}
} else if (it.key() == QStringLiteral("letter-spacing")) {
if (first_val.contains(QChar('%'))) {
fmt.setFontLetterSpacing(
first_val.chopped(1).toDouble());
}
} else if (it.key() == QStringLiteral("font-stretch")) {
if (first_val.contains(QChar('%'))) {
fmt.setFontStretch(first_val.chopped(1).toInt());
}
} else if (it.key() == QStringLiteral("-ove-font-style")) {
fmt.setFontStyleName(first_val);
}
}
}
}
return fmt;
}
QTextBlockFormat Html::read_block_format(const QXmlStreamAttributes &attributes)
{
QTextBlockFormat block_fmt;
foreach (const QXmlStreamAttribute &attr, attributes) {
if (str_equals(attr.name(), QStringLiteral("align"))) {
if (str_equals(attr.value(), QStringLiteral("right"))) {
block_fmt.setAlignment(Qt::AlignRight);
} else if (str_equals(attr.value(), QStringLiteral("center"))) {
block_fmt.setAlignment(Qt::AlignHCenter);
} else if (str_equals(attr.value(), QStringLiteral("justify"))) {
block_fmt.setAlignment(Qt::AlignJustify);
}
} else if (str_equals(attr.name(), QStringLiteral("dir"))) {
if (str_equals(attr.value(), QStringLiteral("rtl"))) {
block_fmt.setLayoutDirection(Qt::RightToLeft);
}
} else if (str_equals(attr.name(), QStringLiteral("style"))) {
auto css = get_css_from_style(attr.value().toString());
for (auto it = css.begin(); it != css.end(); it++) {
if (it.key() == QStringLiteral("line-height")) {
const QString &first_val = it.value().constFirst();
if (first_val.contains(QChar('%'))) {
block_fmt.setLineHeight(
first_val.chopped(1).toDouble(),
QTextBlockFormat::ProportionalHeight);
}
}
}
}
}
return block_fmt;
}
void Html::append_string_auto_space(QString *s, const QString &append)
{
if (!s->isEmpty()) {
s->append(QChar(' '));
}
s->append(append);
}
QMap<QString, QStringList> Html::get_css_from_style(const QString &s)
{
QMap<QString, QStringList> map;
QStringList list = s.split(QChar(';'));
foreach (const QString &a, list) {
QStringList kv = a.split(QChar(':'));
if (kv.size() != 2) {
continue;
}
// I'm sure there's regex that could do this, but I couldn't figure it out. It needs to split
// by space EXCEPT within quotes OR double-quotes, and said quotes should be EXCLUDED from each
// match. Also commas should be filtered out.
QStringList values;
const QString &val = kv.at(1);
QChar in_quote(0);
QString current_str;
for (int i = 0; i < val.size(); i++) {
const QChar &current_char = val.at(i);
if (!in_quote.isNull()) {
// If inside quotes and character isn't quote, indiscriminately append char
if (current_char == in_quote) {
in_quote = QChar(0);
} else {
current_str.append(current_char);
}
} else if (current_char.isSpace() || current_char == QChar(',')) {
// Dump current
if (!current_str.isEmpty()) {
values.append(current_str);
current_str.clear();
}
} else if (in_quote.isNull() && (current_char == QChar('\'') ||
current_char == QChar('"'))) {
in_quote = current_char;
} else {
current_str.append(current_char);
}
}
if (!current_str.isEmpty()) {
values.append(current_str);
}
// Not sure if this will ever happen, but just in case, we will avoid assert failures with this
if (values.isEmpty()) {
values.append(QString());
}
map[kv.at(0).trimmed().toLower()] = values;
}
return map;
}
}
-83
View File
@@ -1,83 +0,0 @@
/*
* Oak Video Editor - Non-Linear Video Editor
* Copyright (C) 2025 Olive CE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OAK_HTML_H
#define OAK_HTML_H
#include <QTextDocument>
#include <QTextFragment>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
namespace olive
{
/**
* @brief Functions for converting HTML to QTextDocument and vice versa
*
* Qt does contain its own functions for this, however they have some limitations. Some things that
* we want to support (e.g. kerning/spacing and font stretch) are not implemented in Qt's
* QTextHtmlExporter and QTextHtmlParser. Additionally, since these functions are not part of Qt's
* public API, and make many references to other parts of Qt that are not part of the public API,
* there is no way to subclass or extend their functionality without forking Qt as a whole.
*
* Therefore, it became necessary to write a custom class for the conversion so that we can
* ensure support for the features we need.
*
* If someone wishes to extend this class for more feature support, feel free to open a pull
* request. But this is NOT intended to be an exhaustive HTML implementation, and is primarily
* designed to store rich text in a standard format for the purpose of text formatting for video.
*/
class Html {
public:
static QString doc_to_html(const QTextDocument *doc);
static void html_to_doc(QTextDocument *doc, const QString &html);
private:
static void write_block(QXmlStreamWriter *writer, const QTextBlock &block);
static void write_fragment(QXmlStreamWriter *writer,
const QTextFragment &fragment);
static void write_css_property(QString *style, const QString &key,
const QStringList &value);
static void write_css_property(QString *style, const QString &key,
const QString &value)
{
write_css_property(style, key, QStringList({ value }));
}
static void write_char_format(QString *style, const QTextCharFormat &fmt);
static QTextCharFormat
read_char_format(const QXmlStreamAttributes &attributes);
static QTextBlockFormat
read_block_format(const QXmlStreamAttributes &attributes);
static void append_string_auto_space(QString *s, const QString &append);
static QMap<QString, QStringList> get_css_from_style(const QString &s);
static const QVector<QString> k_block_tags;
};
}
#endif // OAK_HTML_H
-49
View File
@@ -1,49 +0,0 @@
/*
* Oak Video Editor - Non-Linear Video Editor
* Copyright (C) 2025 Olive CE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jobtime.h"
#include <QMutex>
namespace olive
{
uint64_t job_time_index = 0;
QMutex job_time_mutex;
JobTime::JobTime()
{
acquire();
}
void JobTime::acquire()
{
job_time_mutex.lock();
value_ = job_time_index;
job_time_index++;
job_time_mutex.unlock();
}
}
QDebug operator<<(QDebug debug, const olive::JobTime &r)
{
return debug.space() << r.value();
}
-79
View File
@@ -1,79 +0,0 @@
/*
* Oak Video Editor - Non-Linear Video Editor
* Copyright (C) 2025 Olive CE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OAK_JOBTIME_H
#define OAK_JOBTIME_H
#include <QDebug>
#include <stdint.h>
namespace olive
{
class JobTime {
public:
JobTime();
void acquire();
uint64_t value() const
{
return value_;
}
bool operator==(const JobTime &rhs) const
{
return value_ == rhs.value_;
}
bool operator!=(const JobTime &rhs) const
{
return value_ != rhs.value_;
}
bool operator<(const JobTime &rhs) const
{
return value_ < rhs.value_;
}
bool operator>(const JobTime &rhs) const
{
return value_ > rhs.value_;
}
bool operator<=(const JobTime &rhs) const
{
return value_ <= rhs.value_;
}
bool operator>=(const JobTime &rhs) const
{
return value_ >= rhs.value_;
}
private:
uint64_t value_;
};
}
QDebug operator<<(QDebug debug, const olive::JobTime &r);
Q_DECLARE_METATYPE(olive::JobTime)
#endif // OAK_JOBTIME_H
-42
View File
@@ -1,42 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_LERP_H
#define OAK_LERP_H
template <typename T>
/**
* @brief Linearly interpolate a value between a and b using t
*
* t should be a number between 0.0 and 1.0. 0.0 will return a, 1.0 will return b, and between will return a value
* in between a and b at that point linearly.
*/
T lerp(T a, T b, double t)
{
return (a * (1.0 - t)) + (b * t);
}
template <typename T> T lerp(T a, T b, float t)
{
return (a * (1.0f - t)) + (b * t);
}
#endif // OAK_LERP_H
-438
View File
@@ -1,438 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_MEMORYPOOL_H
#define OAK_MEMORYPOOL_H
#include <memory>
#include <QApplication>
#include <QDateTime>
#include <QDebug>
#include <QMutex>
#include <QTimer>
#include <stdint.h>
#include "common/define.h"
namespace olive
{
/**
* @brief MemoryPool base class
*
* A custom memory system that allocates can allocate several objects in a large chunk (as opposed to several small
* allocations). Improves performance and memory consumption.
*
* As a class, this base is usable by setting the template to an object of your choosing. The pool will then allocate
* `(element_count * sizeof(T))` per arena. Arenas are allocated and destroyed on the fly - when an arena fills up,
* another is allocated.
*
* `Get()` will return an ElementPtr. The original desired data can be accessed through ElementPtr::data(). This data
* will belong to the caller until ElementPtr goes out of scope and the memory is freed back into the pool.
*/
class MemoryPool : public QObject {
Q_OBJECT
public:
/**
* @brief Constructor
* @param element_count
*
* Number of elements per arena
*/
MemoryPool(int element_count)
{
element_count_ = element_count;
clear_timer_ = new QTimer();
clear_timer_->setInterval(kMaxEmptyArenaLife);
clear_timer_->moveToThread(qApp->thread());
connect(clear_timer_, &QTimer::timeout, this,
&MemoryPool::ClearEmptyArenas, Qt::DirectConnection);
QMetaObject::invokeMethod(clear_timer_, "start", Qt::QueuedConnection);
}
/**
* @brief Destructor
*
* Deletes all arenas.
*/
virtual ~MemoryPool()
{
Clear();
clear_timer_->deleteLater();
}
DISABLE_COPY_MOVE(MemoryPool)
/**
* @brief Clears all arenas, freeing all of their memory
*
* Note that this function is not safe, any elements that are still out there will be invalid
* and accessing them will cause a crash. You'll need to make sure all elements are already
* relinquished before then.
*/
void Clear()
{
qDeleteAll(arenas_);
arenas_.clear();
}
/**
* @brief Returns whether any arenas are successfully allocated
*/
inline bool IsAllocated() const
{
return !arenas_.empty();
}
/**
* @brief Returns current number of allocated arenas
*/
inline int GetArenaCount() const
{
return arenas_.size();
}
class Arena;
/**
* @brief A handle for a chunk of memory in an arena
*
* Calling Get() on the pool or arena will return a shared pointer to an element which will contain a pointer to
* the desired object/data in data(). When Element is destroyed (i.e. when ElementPtr goes out of scope), the memory
* is released back into the pool so it can be used by another class.
*/
class Element {
public:
/**
* @brief Element Constructor
*
* There is no need to use this outside of the memory pool's internal functions.
*/
Element(Arena *parent, uint8_t *data)
{
parent_ = parent;
data_ = data;
accessed_ = QDateTime::currentMSecsSinceEpoch();
}
/**
* @brief Element Destructor
*
* Automatically releases this element's memory back to the arena it was retrieved from.
*/
~Element()
{
release();
}
DISABLE_COPY_MOVE(Element)
/**
* @brief Access data represented in the pool
*/
inline uint8_t *data() const
{
return data_;
}
inline const int64_t &timestamp() const
{
return timestamp_;
}
inline void set_timestamp(const int64_t &timestamp)
{
timestamp_ = timestamp;
}
/**
* @brief Register that this element has been accessed
*
* \see last_accessed()
*/
inline void access()
{
accessed_ = QDateTime::currentMSecsSinceEpoch();
}
/**
* @brief Returns the last time `access()` was called on this function
*
* Useful for determining the relative age of an element (i.e. if it hasn't been accessed for a certain amount of
* time, it can probably be freed back into the pool). This requires all usages to call `access()`.
*/
inline const int64_t &last_accessed() const
{
return accessed_;
}
void release()
{
if (data_) {
parent_->Release(this);
data_ = nullptr;
}
}
private:
Arena *parent_;
uint8_t *data_;
int64_t timestamp_;
int64_t accessed_;
};
using ElementPtr = std::shared_ptr<Element>;
/**
* @brief A memory pool arena - a subsection of memory
*
* The pool itself does not store memory, it stores "arenas". This is so that the pool can handle the situation of
* an arena becoming full with no more memory to lend. A pool can automatically allocate another arena and continue
* providing memory (and freeing arenas when they're no longer in use).
*/
class Arena {
public:
Arena(MemoryPool *parent)
{
parent_ = parent;
data_ = nullptr;
allocated_sz_ = 0;
empty_time_ = QDateTime::currentMSecsSinceEpoch();
}
~Arena()
{
std::list<Element *> copy = lent_elements_;
foreach (Element *e, copy) {
e->release();
}
delete[] data_;
}
DISABLE_COPY_MOVE(Arena)
/**
* @brief Returns an element if there is free memory to do so
*/
ElementPtr Get()
{
QMutexLocker locker(&lock_);
for (int i = 0; i < available_.size(); i++) {
if (available_.at(i)) {
// This buffer is available
available_.replace(i, false);
ElementPtr e = std::make_shared<Element>(
this,
reinterpret_cast<uint8_t *>(data_ + i * element_sz_));
lent_elements_.push_back(e.get());
return e;
}
}
return nullptr;
}
/**
* @brief Releases an element back into the pool for use elsewhere
*/
void Release(Element *e)
{
QMutexLocker locker(&lock_);
quintptr diff = reinterpret_cast<quintptr>(e->data()) -
reinterpret_cast<quintptr>(data_);
int index = diff / element_sz_;
available_.replace(index, true);
lent_elements_.remove(e);
if (lent_elements_.empty()) {
empty_time_ = QDateTime::currentMSecsSinceEpoch();
}
}
int GetUsageCount()
{
QMutexLocker locker(&lock_);
return lent_elements_.size();
}
bool Allocate(size_t ele_sz, size_t nb_elements)
{
if (IsAllocated()) {
return true;
}
element_sz_ = ele_sz;
allocated_sz_ = element_sz_ * nb_elements;
if ((data_ = new uint8_t[allocated_sz_])) {
available_.resize(nb_elements);
available_.fill(true);
return true;
} else {
available_.clear();
return false;
}
}
inline int GetElementCount() const
{
return available_.size();
}
inline bool IsAllocated() const
{
return data_;
}
inline qint64 GetTimeArenaWasMadeEmpty()
{
QMutexLocker locker(&lock_);
return empty_time_;
}
private:
MemoryPool *parent_;
uint8_t *data_;
size_t allocated_sz_;
QVector<bool> available_;
QMutex lock_;
size_t element_sz_;
std::list<Element *> lent_elements_;
qint64 empty_time_;
};
/**
* @brief Retrieves an element from an available arena
*/
ElementPtr Get()
{
QMutexLocker locker(&lock_);
// Attempt to get an element from an arena
foreach (Arena *a, arenas_) {
ElementPtr e = a->Get();
if (e) {
return e;
}
}
// All arenas were empty, we'll need to create a new one
if (arenas_.empty()) {
qDebug() << "No arenas, creating new...";
} else {
qDebug() << "All arenas are full, creating new...";
}
size_t ele_sz = GetElementSize();
if (!ele_sz) {
qCritical() << "Failed to create arena, element size was 0";
return nullptr;
}
if (element_count_ <= 0) {
qCritical() << "Failed to create arena, element count was invalid:"
<< element_count_;
return nullptr;
}
Arena *a = new Arena(this);
if (!a->Allocate(ele_sz, element_count_)) {
qCritical()
<< "Failed to create arena, allocation failed. Out of memory?";
delete a;
return nullptr;
}
arenas_.push_back(a);
return a->Get();
}
protected:
/**
* @brief The size of each element
*
* Override this to use a custom size (e.g. a char array where T = char but the element size is > 1)
*/
virtual size_t GetElementSize()
{
return sizeof(uint8_t);
}
private:
int element_count_;
std::list<Arena *> arenas_;
QMutex lock_;
QTimer *clear_timer_;
static const qint64 kMaxEmptyArenaLife = 5000;
private slots:
void ClearEmptyArenas()
{
QMutexLocker locker(&lock_);
const qint64 min_time =
QDateTime::currentMSecsSinceEpoch() - kMaxEmptyArenaLife;
for (auto it = arenas_.begin(); it != arenas_.end();) {
Arena *arena = (*it);
if (arena->GetUsageCount() == 0 &&
arena->GetTimeArenaWasMadeEmpty() <= min_time) {
qDebug() << "Removing an empty arena";
delete arena;
it = arenas_.erase(it);
} else {
it++;
}
}
}
};
}
#endif // OAK_MEMORYPOOL_H
-51
View File
@@ -1,51 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "ocioutils.h"
namespace olive
{
ocio::BitDepth OCIOUtils::get_ocio_bit_depth_from_pixel_format(PixelFormat format)
{
switch (format) {
case PixelFormat::u8:
return ocio::BIT_DEPTH_UINT8;
case PixelFormat::u10:
return ocio::BIT_DEPTH_UINT10;
case PixelFormat::u16:
return ocio::BIT_DEPTH_UINT16;
break;
case PixelFormat::f16:
return ocio::BIT_DEPTH_F16;
break;
case PixelFormat::f32:
return ocio::BIT_DEPTH_F32;
break;
case PixelFormat::invalid:
case PixelFormat::count:
break;
}
return ocio::BIT_DEPTH_UNKNOWN;
}
}
-40
View File
@@ -1,40 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_OCIOUTILS_H
#define OAK_OCIOUTILS_H
#include <OpenColorIO/OpenColorIO.h>
namespace ocio = OCIO_NAMESPACE;
#include "render/videoparams.h"
namespace olive
{
class OCIOUtils {
public:
static ocio::BitDepth get_ocio_bit_depth_from_pixel_format(PixelFormat format);
};
}
#endif // OAK_OCIOUTILS_H
-80
View File
@@ -1,80 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "oiioutils.h"
#include <QDebug>
namespace olive
{
void OIIOUtils::frame_to_buffer(const Frame *frame, OIIO::ImageBuf *buf)
{
buf->set_pixels(OIIO::ROI(), buf->spec().format, frame->const_data(),
OIIO::AutoStride, frame->linesize_bytes());
}
void OIIOUtils::buffer_to_frame(OIIO::ImageBuf *buf, Frame *frame)
{
buf->get_pixels(OIIO::ROI(), buf->spec().format, frame->data(),
OIIO::AutoStride, frame->linesize_bytes());
}
Rational OIIOUtils::get_pixel_aspect_ratio_from_oiio(const OIIO::ImageSpec &spec)
{
return Rational::from_double(
spec.get_float_attribute("PixelAspectRatio", 1));
}
PixelFormat OIIOUtils::get_format_from_oiio_basetype(OIIO::TypeDesc::BASETYPE type)
{
switch (type) {
case OIIO::TypeDesc::UNKNOWN:
case OIIO::TypeDesc::NONE:
break;
case OIIO::TypeDesc::INT8:
case OIIO::TypeDesc::INT16:
case OIIO::TypeDesc::INT32:
case OIIO::TypeDesc::UINT32:
case OIIO::TypeDesc::INT64:
case OIIO::TypeDesc::UINT64:
case OIIO::TypeDesc::STRING:
case OIIO::TypeDesc::PTR:
case OIIO::TypeDesc::LASTBASE:
case OIIO::TypeDesc::DOUBLE:
qDebug() << "Tried to use unknown OIIO base type";
break;
case OIIO::TypeDesc::UINT8:
return PixelFormat::u8;
case OIIO::TypeDesc::UINT16:
return PixelFormat::u16;
case OIIO::TypeDesc::HALF:
return PixelFormat::f16;
case OIIO::TypeDesc::FLOAT:
return PixelFormat::f32;
}
return PixelFormat::invalid;
}
}
-69
View File
@@ -1,69 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_OIIOUTILS_H
#define OAK_OIIOUTILS_H
#include <OpenImageIO/imagebuf.h>
#include <OpenImageIO/typedesc.h>
#include "codec/frame.h"
#include "render/videoparams.h"
namespace olive
{
class OIIOUtils {
public:
static OIIO::TypeDesc::BASETYPE
get_oiio_base_type_from_format(PixelFormat format)
{
switch (format) {
case PixelFormat::u8:
return OIIO::TypeDesc::UINT8;
case PixelFormat::u10:
return OIIO::TypeDesc::UNKNOWN;
case PixelFormat::u16:
return OIIO::TypeDesc::UINT16;
case PixelFormat::f16:
return OIIO::TypeDesc::HALF;
case PixelFormat::f32:
return OIIO::TypeDesc::FLOAT;
case PixelFormat::invalid:
case PixelFormat::count:
break;
}
return OIIO::TypeDesc::UNKNOWN;
}
static void frame_to_buffer(const Frame *frame, OIIO::ImageBuf *buf);
static void buffer_to_frame(OIIO::ImageBuf *buf, Frame *frame);
static PixelFormat get_format_from_oiio_basetype(OIIO::TypeDesc::BASETYPE type);
static Rational get_pixel_aspect_ratio_from_oiio(const OIIO::ImageSpec &spec);
};
}
#endif // OAK_OIIOUTILS_H
-29
View File
@@ -1,29 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_OTIOUTILS_H
#define OAK_OTIOUTILS_H
#ifdef USE_OTIO
#include <opentimelineio/version.h>
namespace OTIO = opentimelineio::OPENTIMELINEIO_VERSION;
#endif
#endif // OTIOUTILS
-45
View File
@@ -1,45 +0,0 @@
/***
Oak - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_PLAYBACKAUDIOCLOCK_H
#define OAK_PLAYBACKAUDIOCLOCK_H
namespace olive
{
/**
* @brief Source of an audio output clock for playback timing
*/
class PlaybackAudioClock {
public:
virtual ~PlaybackAudioClock() = default;
/**
* @brief Seconds of audio consumed by the output device
*
* Must return a negative value when no clocked output is running, in
* which case the caller should fall back to the wall clock.
*/
virtual double seconds() const = 0;
};
}
#endif // OAK_PLAYBACKAUDIOCLOCK_H
-58
View File
@@ -1,58 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_POWER_H
#define OAK_POWER_H
#include <stdint.h>
#include "common/define.h"
namespace olive
{
uint32_t ceil_to_power_of_2(uint32_t v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
uint32_t floor_to_power_of_2(uint32_t x)
{
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x - (x >> 1);
}
}
#endif // OAK_POWER_H
-203
View File
@@ -1,203 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "qtutils.h"
#include <QDebug>
namespace olive
{
int QtUtils::q_font_metrics_width(QFontMetrics fm, const QString &s)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
return fm.width(s);
#else
return fm.horizontalAdvance(s);
#endif
}
QFrame *QtUtils::create_horizontal_line()
{
QFrame *horizontal_line = new QFrame();
horizontal_line->setFrameShape(QFrame::HLine);
horizontal_line->setFrameShadow(QFrame::Sunken);
return horizontal_line;
}
QFrame *QtUtils::create_vertical_line()
{
QFrame *l = create_horizontal_line();
l->setFrameShape(QFrame::VLine);
return l;
}
QDateTime QtUtils::get_creation_date(const QFileInfo &info)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
return info.created();
#else
QDateTime t = info.birthTime();
if (!t.isValid()) {
t = info.metadataChangeTime();
}
return t;
#endif
}
QString QtUtils::get_formatted_date_time(const QDateTime &dt)
{
return dt.toString(Qt::TextDate);
}
QStringList QtUtils::word_wrap_string(const QString &s, const QFontMetrics &fm,
int bounding_width)
{
QStringList list;
QStringList lines = s.split('\n');
// Iterate every line
for (int i = 0; i < lines.size(); i++) {
QString this_line = lines.at(i);
while (this_line.size() > 1 &&
q_font_metrics_width(fm, this_line) >= bounding_width) {
int old_size = this_line.size();
int hard_break = -1;
for (int j = this_line.size() - 1; j >= 0; j--) {
const QChar &char_test = this_line.at(j);
if (char_test.isSpace() || char_test == '-') {
if (q_font_metrics_width(fm, this_line.left(j)) <
bounding_width) {
if (!char_test.isSpace()) {
j++;
}
QString chopped = this_line.left(j);
list.append(chopped);
while (j < this_line.size() &&
this_line.at(j).isSpace()) {
j++;
}
this_line.remove(0, j);
break;
}
} else if (hard_break == -1 &&
q_font_metrics_width(fm, this_line.left(j)) <
bounding_width) {
// In case we can't find a better place to split, split at the earliest time the line
// goes under the width limit
hard_break = j;
}
}
if (old_size == this_line.size()) {
if (hard_break != -1) {
list.append(this_line.left(hard_break));
this_line.remove(0, hard_break);
} else {
qWarning()
<< "Failed to find anywhere to wrap. Returning full line.";
break;
}
}
}
if (!this_line.isEmpty()) {
list.append(this_line);
}
}
return list;
}
Qt::KeyboardModifiers
QtUtils::flip_control_and_shift_modifiers(Qt::KeyboardModifiers e)
{
if (e & Qt::ControlModifier & Qt::ShiftModifier) {
return e;
}
if (e & Qt::ShiftModifier) {
e |= Qt::ControlModifier;
e &= ~Qt::ShiftModifier;
} else if (e & Qt::ControlModifier) {
e |= Qt::ShiftModifier;
e &= ~Qt::ControlModifier;
}
return e;
}
void QtUtils::set_combo_box_data(QComboBox *cb, int data)
{
for (int i = 0; i < cb->count(); i++) {
if (cb->itemData(i).toInt() == data) {
cb->setCurrentIndex(i);
break;
}
}
}
void QtUtils::set_combo_box_data(QComboBox *cb, const QString &data)
{
for (int i = 0; i < cb->count(); i++) {
if (cb->itemData(i).toString() == data) {
cb->setCurrentIndex(i);
break;
}
}
}
QColor QtUtils::to_q_color(const core::Color &i)
{
QColor c;
// QColor only supports values from 0.0 to 1.0 and are only used for UI representations
c.setRedF(std::clamp(i.red(), 0.0f, 1.0f));
c.setGreenF(std::clamp(i.green(), 0.0f, 1.0f));
c.setBlueF(std::clamp(i.blue(), 0.0f, 1.0f));
c.setAlphaF(std::clamp(i.alpha(), 0.0f, 1.0f));
return c;
}
namespace core
{
uint qHash(const core::Rational &r, uint seed)
{
return ::qHash(r.to_double(), seed);
}
uint qHash(const core::TimeRange &r, uint seed)
{
return qHash(r.in(), seed) ^ qHash(r.out(), seed);
}
}
}
-113
View File
@@ -1,113 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_QTVERSIONABSTRACTION_H
#define OAK_QTVERSIONABSTRACTION_H
#include <olive/core/core.h>
#include <QComboBox>
#include <QDateTime>
#include <QFileInfo>
#include <QFontMetrics>
#include <QFrame>
namespace olive
{
class QtUtils {
public:
/**
* @brief Retrieves the width of a string according to certain QFontMetrics
*
* QFontMetrics::width() has been deprecatd in favor of QFontMetrics::horizontalAdvance(), but the
* latter was only introduced in 5.11+. This function wraps the latter for 5.11+ and the former for
* earlier.
*/
static int q_font_metrics_width(QFontMetrics fm, const QString &s);
static QFrame *create_horizontal_line();
static QFrame *create_vertical_line();
static QDateTime get_creation_date(const QFileInfo &info);
static QString get_formatted_date_time(const QDateTime &dt);
static QStringList word_wrap_string(const QString &s, const QFontMetrics &fm,
int bounding_width);
static Qt::KeyboardModifiers
flip_control_and_shift_modifiers(Qt::KeyboardModifiers e);
static void set_combo_box_data(QComboBox *cb, int data);
static void set_combo_box_data(QComboBox *cb, const QString &data);
template <typename T> static T *get_parent_of_type(const QObject *child)
{
QObject *t = child->parent();
while (t) {
if (T *p = dynamic_cast<T *>(t)) {
return p;
}
t = t->parent();
}
return nullptr;
}
static QColor to_q_color(const core::Color &c);
/**
* @brief Convert a pointer to a value that can be sent between NodeParams
*/
static QVariant ptr_to_value(void *ptr)
{
return reinterpret_cast<quintptr>(ptr);
}
/**
* @brief Convert a NodeParam value to a pointer of any kind
*/
template <class T> static T *value_to_ptr(const QVariant &ptr)
{
return reinterpret_cast<T *>(ptr.value<quintptr>());
}
};
namespace core
{
uint qHash(const core::Rational &r, uint seed = 0);
uint qHash(const core::TimeRange &r, uint seed = 0);
}
}
Q_DECLARE_METATYPE(olive::core::Rational)
Q_DECLARE_METATYPE(olive::core::Color)
Q_DECLARE_METATYPE(olive::core::TimeRange)
Q_DECLARE_METATYPE(olive::core::Bezier)
Q_DECLARE_METATYPE(olive::core::AudioParams)
Q_DECLARE_METATYPE(olive::core::SampleBuffer)
#endif // OAK_QTVERSIONABSTRACTION_H
-30
View File
@@ -1,30 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_RANGE_H
#define OAK_RANGE_H
template <typename T> bool in_range(T a, T b, T range)
{
return (a >= b - range && a <= b + range);
}
#endif // OAK_RANGE_H
-42
View File
@@ -1,42 +0,0 @@
/*
* Oak Video Editor - Non-Linear Video Editor
* Copyright (C) 2025 Olive CE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OAK_THREADSAFEMAP_H
#define OAK_THREADSAFEMAP_H
#include <QMap>
#include <QMutex>
template <typename K, typename V> class ThreadSafeMap {
public:
ThreadSafeMap() = default;
void insert(K key, V value)
{
mutex_.lock();
map_.insert(key, value);
mutex_.unlock();
}
private:
QMutex mutex_;
QMap<K, V> map_;
};
#endif // OAK_THREADSAFEMAP_H
-37
View File
@@ -1,37 +0,0 @@
/*
* Oak Video Editor - Non-Linear Video Editor
* Copyright (C) 2025 Olive CE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OAK_TOHEX_H
#define OAK_TOHEX_H
#include <QString>
#include <QtGlobal>
#include "common/define.h"
namespace olive
{
inline QString to_hex(quint64 t)
{
return QStringLiteral("%1").arg(t, 0, 16);
}
}
#endif // OAK_TOHEX_H
-30
View File
@@ -1,30 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_UTIL_H
#define OAK_UTIL_H
template <typename T> inline T mid(T a, T b)
{
return (a + b) * 0.5;
}
#endif // OAK_UTIL_H
-47
View File
@@ -1,47 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "xmlutils.h"
#include "node/block/block.h"
#include "node/factory.h"
namespace olive
{
bool xml_read_next_start_element(QXmlStreamReader *reader, CancelAtom *cancel_atom)
{
QXmlStreamReader::TokenType token;
while ((token = reader->readNext()) != QXmlStreamReader::Invalid &&
token != QXmlStreamReader::EndDocument &&
(!cancel_atom || !cancel_atom->is_cancelled())) {
if (reader->isEndElement()) {
return false;
} else if (reader->isStartElement()) {
return true;
}
}
return false;
}
}
-56
View File
@@ -1,56 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
Modifications Copyright (C) 2025 mikesolar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_XMLREADLOOP_H
#define OAK_XMLREADLOOP_H
#include <QXmlStreamReader>
#include "node/param.h"
#include "render/cancelatom.h"
#include "undo/undocommand.h"
namespace olive
{
class Block;
class Node;
class NodeInput;
class NodeGroup;
#define XMLAttributeLoop(reader, item) \
foreach (const QXmlStreamAttribute &item, reader->attributes())
/**
* @brief Workaround for QXmlStreamReader::readNextStartElement not detecting the end of a document
*
* Since Qt's default function doesn't exit at the end of the document, it ends up consistently
* throwing a "premature end of document" error. We have our own function here that does essentially
* the same thing but fixes that issue.
*
* See also: https://stackoverflow.com/questions/46346450/qt-qxmlstreamreader-always-returns-premature-end-of-document-error
*/
bool xml_read_next_start_element(QXmlStreamReader *reader,
CancelAtom *cancel_atom = nullptr);
}
#endif // OAK_XMLREADLOOP_H