change: change code style to Linux style except indent.

This commit is contained in:
Mike Solar
2025-08-03 03:09:40 +08:00
parent 65ab76edc8
commit 74f73ab3be
789 changed files with 77113 additions and 68888 deletions
+3 -6
View File
@@ -23,15 +23,12 @@
#include "common/define.h"
namespace olive {
namespace olive
{
class AutoScroll {
public:
enum Method {
kNone,
kPage,
kSmooth
};
enum Method { kNone, kPage, kSmooth };
};
}
+22 -20
View File
@@ -24,36 +24,38 @@
#include "common/define.h"
#include "render/cancelatom.h"
namespace olive {
namespace olive
{
class CancelableObject {
public:
CancelableObject()
{
}
CancelableObject()
{
}
void Cancel()
{
cancel_.Cancel();
CancelEvent();
}
void Cancel()
{
cancel_.Cancel();
CancelEvent();
}
CancelAtom *GetCancelAtom()
{
return &cancel_;
}
CancelAtom *GetCancelAtom()
{
return &cancel_;
}
bool IsCancelled()
{
return cancel_.IsCancelled();
}
bool IsCancelled()
{
return cancel_.IsCancelled();
}
protected:
virtual void CancelEvent(){}
virtual void CancelEvent()
{
}
private:
CancelAtom cancel_;
CancelAtom cancel_;
};
}
+106 -98
View File
@@ -25,146 +25,154 @@
CommandLineParser::~CommandLineParser()
{
foreach (const KnownOption& o, options_) {
delete o.option;
}
foreach (const KnownOption &o, options_) {
delete o.option;
}
foreach (const KnownPositionalArgument& a, positional_args_) {
delete a.option;
}
foreach (const KnownPositionalArgument &a, positional_args_) {
delete a.option;
}
}
const CommandLineParser::Option *CommandLineParser::AddOption(const QStringList &strings, const QString &description, bool takes_arg, const QString &arg_placeholder, bool hidden)
const CommandLineParser::Option *
CommandLineParser::AddOption(const QStringList &strings,
const QString &description, bool takes_arg,
const QString &arg_placeholder, bool hidden)
{
Option* o = new Option();
Option *o = new Option();
options_.append({strings, description, o, takes_arg, arg_placeholder, hidden});
options_.append(
{ strings, description, o, takes_arg, arg_placeholder, hidden });
return o;
return o;
}
const CommandLineParser::PositionalArgument *CommandLineParser::AddPositionalArgument(const QString &name, const QString &description, bool required)
const CommandLineParser::PositionalArgument *
CommandLineParser::AddPositionalArgument(const QString &name,
const QString &description,
bool required)
{
PositionalArgument* a = new PositionalArgument();
PositionalArgument *a = new PositionalArgument();
positional_args_.append({name, description, a, required});
positional_args_.append({ name, description, a, required });
return a;
return a;
}
void CommandLineParser::Process(const QVector<QString> &argv)
{
int positional_index = 0;
int positional_index = 0;
for (int i=1; i<argv.size(); i++) {
if (argv[i][0] == '-') {
// Must be an option
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);
// Skip past first dashes
QString arg_basename = argv[i].mid(1);
bool matched_known = false;
bool matched_known = false;
for (int j=0; j<options_.size(); j++) {
KnownOption& o = options_[j];
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();
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->SetSetting(argv[i+1]);
i++;
}
if (o.takes_arg && i + 1 < argv.size()) {
o.option->SetSetting(argv[i + 1]);
i++;
}
matched_known = true;
goto found_flag;
}
}
}
matched_known = true;
goto found_flag;
}
}
}
found_flag:
if (!matched_known) {
qWarning() << "Unknown parameter:" << argv[i];
}
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->SetSetting(argv[i]);
positional_index++;
} else {
qWarning() << "Unknown parameter:" << argv[i];
}
}
}
} else {
// Must be a positional flag
if (positional_index < positional_args_.size()) {
positional_args_[positional_index].option->SetSetting(argv[i]);
positional_index++;
} else {
qWarning() << "Unknown parameter:" << argv[i];
}
}
}
}
void CommandLineParser::PrintHelp(const char* filename)
void CommandLineParser::PrintHelp(const char *filename)
{
printf("%s %s\n",
QCoreApplication::applicationName().toUtf8().constData(),
QCoreApplication::applicationVersion().toUtf8().constData());
printf("%s %s\n", QCoreApplication::applicationName().toUtf8().constData(),
QCoreApplication::applicationVersion().toUtf8().constData());
printf("Copyright (C) 2018-2022 Olive Team\n");
printf("Copyright (C) 2018-2022 Olive Team\n");
QString positional_args;
for (int i=0; i<positional_args_.size(); i++) {
if (i > 0) {
positional_args.append(' ');
}
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(']');
}
positional_args.append('[');
positional_args.append(positional_args_.at(i).name);
positional_args.append(']');
}
const char* basename;
const char *basename;
#ifdef Q_OS_WINDOWS
basename = strrchr(filename, '\\');
if (!basename) {
basename = strrchr(filename, '/');
}
basename = strrchr(filename, '\\');
if (!basename) {
basename = strrchr(filename, '/');
}
#else
basename = strrchr(filename, '/');
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;
}
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;
}
printf("Usage: %s [options] %s\n\n", basename,
positional_args.toUtf8().constData());
foreach (const KnownOption &o, options_) {
if (o.hidden) {
continue;
}
QString all_args;
QString all_args;
for (int i=0; i<o.args.size(); i++) {
if (i > 0) {
all_args.append(QStringLiteral(", "));
}
for (int i = 0; i < o.args.size(); i++) {
if (i > 0) {
all_args.append(QStringLiteral(", "));
}
const QString& this_arg = o.args.at(i);
const QString &this_arg = o.args.at(i);
all_args.append('-');
all_args.append(this_arg);
}
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());
}
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(" %s\n\n", o.description.toUtf8().constData());
}
printf("\n");
printf("\n");
}
+60 -60
View File
@@ -36,86 +36,86 @@
* 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
{
class CommandLineParser {
public:
~CommandLineParser();
~CommandLineParser();
DISABLE_COPY_MOVE(CommandLineParser)
DISABLE_COPY_MOVE(CommandLineParser)
class PositionalArgument
{
public:
PositionalArgument() = default;
class PositionalArgument {
public:
PositionalArgument() = default;
const QString& GetSetting() const
{
return setting_;
}
const QString &GetSetting() const
{
return setting_;
}
void SetSetting(const QString& s)
{
setting_ = s;
}
void SetSetting(const QString &s)
{
setting_ = s;
}
private:
QString setting_;
private:
QString setting_;
};
};
class Option : public PositionalArgument {
public:
Option()
{
is_set_ = false;
}
class Option : public PositionalArgument {
public:
Option()
{
is_set_ = false;
}
bool IsSet() const
{
return is_set_;
}
bool IsSet() const
{
return is_set_;
}
void Set()
{
is_set_ = true;
}
void Set()
{
is_set_ = true;
}
private:
bool is_set_;
};
private:
bool is_set_;
CommandLineParser() = default;
};
const Option *AddOption(const QStringList &strings,
const QString &description, bool takes_arg = false,
const QString &arg_placeholder = QString(),
bool hidden = false);
CommandLineParser() = default;
const PositionalArgument *AddPositionalArgument(const QString &name,
const QString &description,
bool required = false);
const Option* AddOption(const QStringList& strings, const QString& description, bool takes_arg = false, const QString& arg_placeholder = QString(), bool hidden = false);
void Process(const QVector<QString> &argv);
const PositionalArgument* AddPositionalArgument(const QString& name, const QString& description, bool required = false);
void Process(const QVector<QString> &argv);
void PrintHelp(const char* filename);
void PrintHelp(const char *filename);
private:
struct KnownOption {
QStringList args;
QString description;
Option* option;
bool takes_arg;
QString arg_placeholder;
bool hidden;
};
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;
};
struct KnownPositionalArgument {
QString name;
QString description;
PositionalArgument *option;
bool required;
};
QVector<KnownOption> options_;
QVector<KnownPositionalArgument> positional_args_;
QVector<KnownOption> options_;
QVector<KnownPositionalArgument> positional_args_;
};
#endif // COMMANDLINEPARSER_H
+44 -33
View File
@@ -40,52 +40,63 @@ crashpad::CrashpadClient *client;
bool InitializeCrashpad()
{
QString report_path = QDir(olive::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("reports"));
QString report_path = QDir(olive::FileFunctions::GetTempFilePath())
.filePath(QStringLiteral("reports"));
QString handler_fn = olive::FileFunctions::GetFormattedExecutableForPlatform(QStringLiteral("crashpad_handler"));
QString handler_fn =
olive::FileFunctions::GetFormattedExecutableForPlatform(
QStringLiteral("crashpad_handler"));
// Generate absolute path
QString handler_abs_path = QDir(QCoreApplication::applicationDirPath()).filePath(handler_fn);
// Generate absolute path
QString handler_abs_path =
QDir(QCoreApplication::applicationDirPath()).filePath(handler_fn);
bool status = false;
bool status = false;
if (QFileInfo::exists(handler_abs_path)) {
base::FilePath handler(QSTRING_TO_BASE_STRING(handler_abs_path));
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 reports_dir(QSTRING_TO_BASE_STRING(report_path));
base::FilePath metrics_dir(QSTRING_TO_BASE_STRING(QDir(olive::FileFunctions::GetTempFilePath()).filePath(QStringLiteral("metrics"))));
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;
// 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");
// 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;
// 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);
// 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);
}
// 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";
}
// Override Crashpad exception filter with our own
if (!status) {
qWarning()
<< "Failed to start Crashpad, automatic crash reporting will be disabled";
}
return status;
return status;
}
#endif // USE_CRASHPAD
+1 -1
View File
@@ -35,6 +35,6 @@
// 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 // BUILDFLAG(IS_WIN)
#endif // CRASHPADUTILS_H
+29 -27
View File
@@ -20,38 +20,40 @@
#include "debug.h"
namespace olive {
void DebugHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
namespace olive
{
QByteArray localMsg = 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;
}
void DebugHandler(QtMsgType type, const QMessageLogContext &context,
const QString &msg)
{
QByteArray localMsg = msg.toLocal8Bit();
//fprintf(stderr, "[%s] %s (%s:%u)\n", msg_type, localMsg.constData(), context.function, context.line);
fprintf(stderr, "[%s] %s\n", msg_type, localMsg.constData());
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, localMsg.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);
// 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
}
+4 -2
View File
@@ -25,9 +25,11 @@
#include "common/define.h"
namespace olive {
namespace olive
{
void DebugHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
void DebugHandler(QtMsgType type, const QMessageLogContext &context,
const QString &msg);
}
+54 -55
View File
@@ -26,77 +26,76 @@
//#define ALLOW_RETURNING_INFINITY
namespace olive {
class Decibel
namespace olive
{
class Decibel {
public:
// In basically all circumstances, this should calculate to 0.0 linear
static constexpr double MINIMUM = -200.0;
// In basically all circumstances, this should calculate to 0.0 linear
static constexpr double MINIMUM = -200.0;
static double fromLinear(double linear)
{
double v = double(20.0) * std::log10(linear);
static double fromLinear(double linear)
{
double v = double(20.0) * std::log10(linear);
#ifndef ALLOW_RETURNING_INFINITY
if (std::isinf(v)) {
return MINIMUM;
}
if (std::isinf(v)) {
return MINIMUM;
}
#endif
return v;
}
return v;
}
static double toLinear(double decibel)
{
double to_linear = std::pow(double(10.0), decibel / double(20.0));
static double toLinear(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;
}
}
// 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 fromLogarithmic(double logarithmic)
{
if (logarithmic < 0.001)
static double fromLogarithmic(double logarithmic)
{
if (logarithmic < 0.001)
#ifdef ALLOW_RETURNING_INFINITY
return std::numeric_limits<double>::infinity();
return std::numeric_limits<double>::infinity();
#else
return MINIMUM;
return MINIMUM;
#endif
else if (logarithmic > 0.99)
return 0;
else
return 20.0 * std::log10(-std::log(1 - logarithmic) / LOG100);
}
else if (logarithmic > 0.99)
return 0;
else
return 20.0 * std::log10(-std::log(1 - logarithmic) / LOG100);
}
static double toLogarithmic(double decibel)
{
if (qFuzzyIsNull(decibel)) {
return 1;
} else {
return 1 - std::exp(-std::pow(10.0, decibel / 20.0) * LOG100);
}
}
static double toLogarithmic(double decibel)
{
if (qFuzzyIsNull(decibel)) {
return 1;
} else {
return 1 - std::exp(-std::pow(10.0, decibel / 20.0) * LOG100);
}
}
static double LinearToLogarithmic(double linear)
{
return 1 - std::exp(-linear * LOG100);
}
static double LinearToLogarithmic(double linear)
{
return 1 - std::exp(-linear * LOG100);
}
static double LogarithmicToLinear(double logarithmic)
{
if (logarithmic > 0.99) {
return 1;
} else {
return -std::log(1 - logarithmic) / LOG100;
}
}
static double LogarithmicToLinear(double logarithmic)
{
if (logarithmic > 0.99) {
return 1;
} else {
return -std::log(1 - logarithmic) / LOG100;
}
}
private:
static constexpr double LOG100 = 4.60517018599;
static constexpr double LOG100 = 4.60517018599;
};
}
+16 -12
View File
@@ -21,7 +21,8 @@
#ifndef OLIVECOMMONDEFINE_H
#define OLIVECOMMONDEFINE_H
namespace olive {
namespace olive
{
/// The minimum size an icon in ProjectExplorer can be
const int kProjectIconSizeMinimum = 16;
@@ -39,25 +40,28 @@ const int kBytesInGigabyte = 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)
#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_COPY(Class) \
Class(const Class &) = delete; \
Class &operator=(const Class &) = delete;
#define DISABLE_MOVE(Class) \
Class(Class &&) = delete; \
Class &operator=(Class &&) = delete;
#define DISABLE_MOVE(Class) \
Class(Class &&) = delete; \
Class &operator=(Class &&) = delete;
#define DISABLE_COPY_MOVE(Class) \
DISABLE_COPY(Class) \
DISABLE_MOVE(Class)
DISABLE_COPY(Class) \
DISABLE_MOVE(Class)
#endif // OLIVECOMMONDEFINE_H
+10 -9
View File
@@ -23,21 +23,22 @@
#include <stdint.h>
namespace olive {
namespace olive
{
inline int64_t GetDigitCount(int64_t input)
{
input = std::abs(input);
input = std::abs(input);
int64_t lim = 10;
int64_t digit = 1;
int64_t lim = 10;
int64_t digit = 1;
while (input >= lim) {
lim *= 10;
digit++;
}
while (input >= lim) {
lim *= 10;
digit++;
}
return digit;
return digit;
}
}
+148 -141
View File
@@ -20,180 +20,187 @@
#include "common/ffmpegutils.h"
namespace olive {
AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt, PixelFormat maximum)
namespace olive
{
AVPixelFormat possible_pix_fmts[3];
possible_pix_fmts[0] = AV_PIX_FMT_RGBA;
AVPixelFormat
FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt,
PixelFormat maximum)
{
AVPixelFormat possible_pix_fmts[3];
if (maximum == PixelFormat::U8) {
possible_pix_fmts[1] = AV_PIX_FMT_NONE;
} else {
possible_pix_fmts[1] = AV_PIX_FMT_RGBA64;
possible_pix_fmts[2] = AV_PIX_FMT_NONE;
}
possible_pix_fmts[0] = AV_PIX_FMT_RGBA;
return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts,
pix_fmt,
1,
nullptr);
if (maximum == PixelFormat::U8) {
possible_pix_fmts[1] = AV_PIX_FMT_NONE;
} else {
possible_pix_fmts[1] = AV_PIX_FMT_RGBA64;
possible_pix_fmts[2] = AV_PIX_FMT_NONE;
}
return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts, pix_fmt, 1,
nullptr);
}
SampleFormat FFmpegUtils::GetNativeSampleFormat(const AVSampleFormat &smp_fmt)
{
switch (smp_fmt) {
case AV_SAMPLE_FMT_U8:
return SampleFormat::U8;
case AV_SAMPLE_FMT_S16:
return SampleFormat::S16;
case AV_SAMPLE_FMT_S32:
return SampleFormat::S32;
case AV_SAMPLE_FMT_S64:
return SampleFormat::S64;
case AV_SAMPLE_FMT_FLT:
return SampleFormat::F32;
case AV_SAMPLE_FMT_DBL:
return SampleFormat::F64;
case AV_SAMPLE_FMT_U8P :
return SampleFormat::U8P;
case AV_SAMPLE_FMT_S16P:
return SampleFormat::S16P;
case AV_SAMPLE_FMT_S32P:
return SampleFormat::S32P;
case AV_SAMPLE_FMT_S64P:
return SampleFormat::S64P;
case AV_SAMPLE_FMT_FLTP:
return SampleFormat::F32P;
case AV_SAMPLE_FMT_DBLP:
return SampleFormat::F64P;
case AV_SAMPLE_FMT_NONE:
case AV_SAMPLE_FMT_NB:
break;
}
switch (smp_fmt) {
case AV_SAMPLE_FMT_U8:
return SampleFormat::U8;
case AV_SAMPLE_FMT_S16:
return SampleFormat::S16;
case AV_SAMPLE_FMT_S32:
return SampleFormat::S32;
case AV_SAMPLE_FMT_S64:
return SampleFormat::S64;
case AV_SAMPLE_FMT_FLT:
return SampleFormat::F32;
case AV_SAMPLE_FMT_DBL:
return SampleFormat::F64;
case AV_SAMPLE_FMT_U8P:
return SampleFormat::U8P;
case AV_SAMPLE_FMT_S16P:
return SampleFormat::S16P;
case AV_SAMPLE_FMT_S32P:
return SampleFormat::S32P;
case AV_SAMPLE_FMT_S64P:
return SampleFormat::S64P;
case AV_SAMPLE_FMT_FLTP:
return SampleFormat::F32P;
case AV_SAMPLE_FMT_DBLP:
return SampleFormat::F64P;
case AV_SAMPLE_FMT_NONE:
case AV_SAMPLE_FMT_NB:
break;
}
return SampleFormat::INVALID;
return SampleFormat::INVALID;
}
AVSampleFormat FFmpegUtils::GetFFmpegSampleFormat(const SampleFormat &smp_fmt)
{
switch (smp_fmt) {
case SampleFormat::U8:
return AV_SAMPLE_FMT_U8;
case SampleFormat::S16:
return AV_SAMPLE_FMT_S16;
case SampleFormat::S32:
return AV_SAMPLE_FMT_S32;
case SampleFormat::S64:
return AV_SAMPLE_FMT_S64;
case SampleFormat::F32:
return AV_SAMPLE_FMT_FLT;
case SampleFormat::F64:
return AV_SAMPLE_FMT_DBL;
case SampleFormat::U8P:
return AV_SAMPLE_FMT_U8P;
case SampleFormat::S16P:
return AV_SAMPLE_FMT_S16P;
case SampleFormat::S32P:
return AV_SAMPLE_FMT_S32P;
case SampleFormat::S64P:
return AV_SAMPLE_FMT_S64P;
case SampleFormat::F32P:
return AV_SAMPLE_FMT_FLTP;
case SampleFormat::F64P:
return AV_SAMPLE_FMT_DBLP;
case SampleFormat::INVALID:
case SampleFormat::COUNT:
break;
}
switch (smp_fmt) {
case SampleFormat::U8:
return AV_SAMPLE_FMT_U8;
case SampleFormat::S16:
return AV_SAMPLE_FMT_S16;
case SampleFormat::S32:
return AV_SAMPLE_FMT_S32;
case SampleFormat::S64:
return AV_SAMPLE_FMT_S64;
case SampleFormat::F32:
return AV_SAMPLE_FMT_FLT;
case SampleFormat::F64:
return AV_SAMPLE_FMT_DBL;
case SampleFormat::U8P:
return AV_SAMPLE_FMT_U8P;
case SampleFormat::S16P:
return AV_SAMPLE_FMT_S16P;
case SampleFormat::S32P:
return AV_SAMPLE_FMT_S32P;
case SampleFormat::S64P:
return AV_SAMPLE_FMT_S64P;
case SampleFormat::F32P:
return AV_SAMPLE_FMT_FLTP;
case SampleFormat::F64P:
return AV_SAMPLE_FMT_DBLP;
case SampleFormat::INVALID:
case SampleFormat::COUNT:
break;
}
return AV_SAMPLE_FMT_NONE;
return AV_SAMPLE_FMT_NONE;
}
int FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVColorSpace cs)
{
switch (cs) {
case AVCOL_SPC_BT709:
return SWS_CS_ITU709;
case AVCOL_SPC_FCC:
return SWS_CS_FCC;
case AVCOL_SPC_BT470BG:
return SWS_CS_ITU624;
case AVCOL_SPC_SMPTE170M:
return SWS_CS_SMPTE170M;
case AVCOL_SPC_SMPTE240M:
return SWS_CS_SMPTE240M;
case AVCOL_SPC_BT2020_NCL:
return SWS_CS_BT2020;
default:
break;
}
switch (cs) {
case AVCOL_SPC_BT709:
return SWS_CS_ITU709;
case AVCOL_SPC_FCC:
return SWS_CS_FCC;
case AVCOL_SPC_BT470BG:
return SWS_CS_ITU624;
case AVCOL_SPC_SMPTE170M:
return SWS_CS_SMPTE170M;
case AVCOL_SPC_SMPTE240M:
return SWS_CS_SMPTE240M;
case AVCOL_SPC_BT2020_NCL:
return SWS_CS_BT2020;
default:
break;
}
return SWS_CS_DEFAULT;
return SWS_CS_DEFAULT;
}
AVPixelFormat FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AVPixelFormat f)
{
switch (f) {
case AV_PIX_FMT_YUVJ420P: return AV_PIX_FMT_YUV420P;
case AV_PIX_FMT_YUVJ422P: return AV_PIX_FMT_YUV422P;
case AV_PIX_FMT_YUVJ444P: return AV_PIX_FMT_YUV444P;
case AV_PIX_FMT_YUVJ440P: return AV_PIX_FMT_YUV440P;
case AV_PIX_FMT_YUVJ411P: return AV_PIX_FMT_YUV411P;
default:
break;
}
switch (f) {
case AV_PIX_FMT_YUVJ420P:
return AV_PIX_FMT_YUV420P;
case AV_PIX_FMT_YUVJ422P:
return AV_PIX_FMT_YUV422P;
case AV_PIX_FMT_YUVJ444P:
return AV_PIX_FMT_YUV444P;
case AV_PIX_FMT_YUVJ440P:
return AV_PIX_FMT_YUV440P;
case AV_PIX_FMT_YUVJ411P:
return AV_PIX_FMT_YUV411P;
default:
break;
}
return f;
return f;
}
AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const PixelFormat &pix_fmt, int channel_layout)
AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const PixelFormat &pix_fmt,
int channel_layout)
{
if (channel_layout == VideoParams::kRGBChannelCount) {
switch (pix_fmt) {
case PixelFormat::U8:
return AV_PIX_FMT_RGB24;
case PixelFormat::U16:
return AV_PIX_FMT_RGB48;
case PixelFormat::F16:
case PixelFormat::F32:
case PixelFormat::INVALID:
case PixelFormat::COUNT:
break;
}
} else if (channel_layout == VideoParams::kRGBAChannelCount) {
switch (pix_fmt) {
case PixelFormat::U8:
return AV_PIX_FMT_RGBA;
case PixelFormat::U16:
return AV_PIX_FMT_RGBA64;
case PixelFormat::F16:
case PixelFormat::F32:
case PixelFormat::INVALID:
case PixelFormat::COUNT:
break;
}
}
if (channel_layout == VideoParams::kRGBChannelCount) {
switch (pix_fmt) {
case PixelFormat::U8:
return AV_PIX_FMT_RGB24;
case PixelFormat::U16:
return AV_PIX_FMT_RGB48;
case PixelFormat::F16:
case PixelFormat::F32:
case PixelFormat::INVALID:
case PixelFormat::COUNT:
break;
}
} else if (channel_layout == VideoParams::kRGBAChannelCount) {
switch (pix_fmt) {
case PixelFormat::U8:
return AV_PIX_FMT_RGBA;
case PixelFormat::U16:
return AV_PIX_FMT_RGBA64;
case PixelFormat::F16:
case PixelFormat::F32:
case PixelFormat::INVALID:
case PixelFormat::COUNT:
break;
}
}
return AV_PIX_FMT_NONE;
return AV_PIX_FMT_NONE;
}
PixelFormat FFmpegUtils::GetCompatiblePixelFormat(const PixelFormat &pix_fmt)
{
switch (pix_fmt) {
case PixelFormat::U8:
return PixelFormat::U8;
case PixelFormat::U16:
case PixelFormat::F16:
case PixelFormat::F32:
return PixelFormat::U16;
case PixelFormat::INVALID:
case PixelFormat::COUNT:
break;
}
switch (pix_fmt) {
case PixelFormat::U8:
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;
return PixelFormat::INVALID;
}
}
+21 -17
View File
@@ -31,63 +31,67 @@ extern "C" {
#include "render/videoparams.h"
namespace olive {
namespace olive
{
using namespace core;
class FFmpegUtils {
public:
/**
/**
* @brief Returns an AVPixelFormat that can be used to convert a frame to a data type Olive supports with minimal data loss
*/
static AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt, PixelFormat maximum = PixelFormat::INVALID);
static AVPixelFormat
GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt,
PixelFormat maximum = PixelFormat::INVALID);
/**
/**
* @brief Returns a native pixel format that can be used to convert from a native frame to an AVFrame with minimal data loss
*/
static PixelFormat GetCompatiblePixelFormat(const PixelFormat& pix_fmt);
static PixelFormat GetCompatiblePixelFormat(const PixelFormat &pix_fmt);
/**
/**
* @brief Returns an FFmpeg pixel format for a given native pixel format
*/
static AVPixelFormat GetFFmpegPixelFormat(const PixelFormat& pix_fmt, int channel_layout);
static AVPixelFormat GetFFmpegPixelFormat(const PixelFormat &pix_fmt,
int channel_layout);
/**
/**
* @brief Returns a native sample format type for a given AVSampleFormat
*/
static SampleFormat GetNativeSampleFormat(const AVSampleFormat& smp_fmt);
static SampleFormat GetNativeSampleFormat(const AVSampleFormat &smp_fmt);
/**
/**
* @brief Returns an FFmpeg sample format type for a given native type
*/
static AVSampleFormat GetFFmpegSampleFormat(const SampleFormat &smp_fmt);
static AVSampleFormat GetFFmpegSampleFormat(const SampleFormat &smp_fmt);
/**
/**
* @brief Returns an SWS_CS_* macro from an AVColorSpace enum member
*
* Why aren't these the same thing anyway? And for that matter, why doesn't FFmpeg provide a
* convenience function to do this conversion for us? Who knows, but here we are.
*/
static int GetSwsColorspaceFromAVColorSpace(AVColorSpace cs);
static int GetSwsColorspaceFromAVColorSpace(AVColorSpace cs);
/**
/**
* @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 AVPixelFormat ConvertJPEGSpaceToRegularSpace(AVPixelFormat f);
static AVPixelFormat ConvertJPEGSpaceToRegularSpace(AVPixelFormat f);
};
using AVFramePtr = std::shared_ptr<AVFrame>;
inline AVFramePtr CreateAVFramePtr(AVFrame *f)
{
return std::shared_ptr<AVFrame>(f, [](AVFrame *g){ av_frame_free(&g); });
return std::shared_ptr<AVFrame>(f, [](AVFrame *g) { av_frame_free(&g); });
}
inline AVFramePtr CreateAVFramePtr()
{
return CreateAVFramePtr(av_frame_alloc());
return CreateAVFramePtr(av_frame_alloc());
}
}
+142 -125
View File
@@ -29,206 +29,223 @@
#include "config/config.h"
namespace olive {
namespace olive
{
QString FileFunctions::GetUniqueFileIdentifier(const QString &filename)
{
QFileInfo info(filename);
QFileInfo info(filename);
if (!info.exists()) {
return QString();
}
if (!info.exists()) {
return QString();
}
QCryptographicHash hash(QCryptographicHash::Sha1);
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(info.absoluteFilePath().toUtf8());
hash.addData(info.absoluteFilePath().toUtf8());
hash.addData(QString::number(info.lastModified().toMSecsSinceEpoch()).toUtf8());
hash.addData(
QString::number(info.lastModified().toMSecsSinceEpoch()).toUtf8());
QByteArray result = hash.result();
QByteArray result = hash.result();
return QString(result.toHex());
return QString(result.toHex());
}
QString FileFunctions::GetConfigurationLocation()
{
if (IsPortable()) {
return GetApplicationPath();
} else {
QString s = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir(s).mkpath(".");
return s;
}
if (IsPortable()) {
return GetApplicationPath();
} else {
QString s =
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir(s).mkpath(".");
return s;
}
}
bool FileFunctions::IsPortable()
{
return QFileInfo::exists(QDir(GetApplicationPath()).filePath("portable"));
return QFileInfo::exists(QDir(GetApplicationPath()).filePath("portable"));
}
QString FileFunctions::GetApplicationPath()
{
return QCoreApplication::applicationDirPath();
return QCoreApplication::applicationDirPath();
}
QString FileFunctions::GetTempFilePath()
{
QString temp_path = QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation))
.filePath(QCoreApplication::organizationName()))
.filePath(QCoreApplication::applicationName());
QString temp_path =
QDir(
QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation))
.filePath(QCoreApplication::organizationName()))
.filePath(QCoreApplication::applicationName());
// Ensure it exists
QDir(temp_path).mkpath(".");
// Ensure it exists
QDir(temp_path).mkpath(".");
return temp_path;
return temp_path;
}
bool FileFunctions::CanCopyDirectoryWithoutOverwriting(const QString& source, const QString& dest)
bool FileFunctions::CanCopyDirectoryWithoutOverwriting(const QString &source,
const QString &dest)
{
QFileInfoList info_list = QDir(source).entryInfoList();
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;
}
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());
QString dest_equivalent = QDir(dest).filePath(info.fileName());
if (info.isDir()) {
if (!CanCopyDirectoryWithoutOverwriting(info.absoluteFilePath(), dest_equivalent)) {
return false;
}
} else if (QFileInfo::exists(dest_equivalent)) {
return false;
}
}
if (info.isDir()) {
if (!CanCopyDirectoryWithoutOverwriting(info.absoluteFilePath(),
dest_equivalent)) {
return false;
}
} else if (QFileInfo::exists(dest_equivalent)) {
return false;
}
}
return true;
return true;
}
void FileFunctions::CopyDirectory(const QString &source, const QString &dest, bool overwrite)
void FileFunctions::CopyDirectory(const QString &source, const QString &dest,
bool overwrite)
{
QDir d(source);
QDir d(source);
if (!d.exists()) {
qCritical() << "Failed to copy directory, source" << source << "didn't exist";
return;
}
if (!d.exists()) {
qCritical()
<< "Failed to copy directory, source" << source << "didn't exist";
return;
}
QDir dest_dir(dest);
QDir dest_dir(dest);
if (!dest_dir.mkpath(QStringLiteral("."))) {
qCritical() << "Failed to create destination directory" << dest;
return;
}
if (!dest_dir.mkpath(QStringLiteral("."))) {
qCritical() << "Failed to create destination directory" << dest;
return;
}
QFileInfoList l = d.entryInfoList();
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;
}
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());
QString dest_file_path = dest_dir.filePath(info.fileName());
if (info.isDir()) {
// Copy dir
CopyDirectory(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();
}
if (info.isDir()) {
// Copy dir
CopyDirectory(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);
}
}
QFile::copy(info.absoluteFilePath(), dest_file_path);
}
}
}
bool FileFunctions::DirectoryIsValid(const QDir &d, bool try_to_create_if_not_exists)
bool FileFunctions::DirectoryIsValid(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() || d.mkpath(QStringLiteral("."));
// Return whether the directory exists, or whether it could be created if it doesn't
return d.exists() || d.mkpath(QStringLiteral("."));
}
QString FileFunctions::EnsureFilenameExtension(QString fn, const QString &extension)
QString FileFunctions::EnsureFilenameExtension(QString fn,
const QString &extension)
{
// No-op if either input is empty
if (!fn.isEmpty() && !extension.isEmpty()) {
QString extension_with_dot;
// 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);
extension_with_dot.append('.');
extension_with_dot.append(extension);
if (!fn.endsWith(extension_with_dot, Qt::CaseInsensitive)) {
fn.append(extension_with_dot);
}
}
if (!fn.endsWith(extension_with_dot, Qt::CaseInsensitive)) {
fn.append(extension_with_dot);
}
}
return fn;
return fn;
}
QString FileFunctions::ReadFileAsString(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;
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::GetSafeTemporaryFilename(const QString &original)
{
int counter = 0;
int counter = 0;
QFileInfo original_info(original);
QString basename = original_info.baseName();
QString complete_suffix = original_info.completeSuffix();
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('.');
}
// 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));
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;
return temp_abs_path;
}
bool FileFunctions::RenameFileAllowOverwrite(const QString &from, const QString &to)
bool FileFunctions::RenameFileAllowOverwrite(const QString &from,
const QString &to)
{
if (QFileInfo::exists(to) && !QFile::remove(to)) {
qCritical() << "Couldn't remove existing file" << to << "for overwrite";
return false;
}
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;
}
// 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;
return true;
}
QString FileFunctions::GetAutoRecoveryRoot()
{
return QDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(QStringLiteral("autorecovery"));
return QDir(QStandardPaths::writableLocation(
QStandardPaths::AppLocalDataLocation))
.filePath(QStringLiteral("autorecovery"));
}
}
+29 -26
View File
@@ -26,36 +26,40 @@
#include "common/define.h"
namespace olive {
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 IsPortable();
static bool IsPortable();
static QString GetUniqueFileIdentifier(const QString& filename);
static QString GetUniqueFileIdentifier(const QString &filename);
static QString GetConfigurationLocation();
static QString GetConfigurationLocation();
static QString GetApplicationPath();
static QString GetApplicationPath();
static QString GetTempFilePath();
static QString GetTempFilePath();
static bool CanCopyDirectoryWithoutOverwriting(const QString& source, const QString& dest);
static bool CanCopyDirectoryWithoutOverwriting(const QString &source,
const QString &dest);
static void CopyDirectory(const QString& source, const QString& dest, bool overwrite = false);
static void CopyDirectory(const QString &source, const QString &dest,
bool overwrite = false);
static bool DirectoryIsValid(const QDir& dir, bool try_to_create_if_not_exists = true);
static bool DirectoryIsValid(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
@@ -64,11 +68,12 @@ public:
* @return The filename provided either untouched or with the extension appended to it.
*/
static QString EnsureFilenameExtension(QString fn, const QString& extension);
static QString EnsureFilenameExtension(QString fn,
const QString &extension);
static QString ReadFileAsString(const QString& filename);
static QString ReadFileAsString(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
@@ -78,28 +83,26 @@ public:
* 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 GetSafeTemporaryFilename(const QString& original);
static QString GetSafeTemporaryFilename(const QString &original);
/**
/**
* @brief Renames a file from `from` to `to`, deleting `to` if such a file already exists first
*/
static bool RenameFileAllowOverwrite(const QString& from, const QString& to);
static bool RenameFileAllowOverwrite(const QString &from,
const QString &to);
inline static QString GetFormattedExecutableForPlatform(QString unformatted)
{
inline static QString GetFormattedExecutableForPlatform(QString unformatted)
{
#ifdef Q_OS_WINDOWS
unformatted.append(QStringLiteral(".exe"));
unformatted.append(QStringLiteral(".exe"));
#endif
return unformatted;
}
static QString GetAutoRecoveryRoot();
return unformatted;
}
static QString GetAutoRecoveryRoot();
};
}
#endif // FILEFUNCTIONS_H
+349 -323
View File
@@ -5,446 +5,472 @@
#include "xmlutils.h"
namespace olive {
namespace olive
{
const QVector<QString> Html::kBlockTags = {
QStringLiteral("p"),
QStringLiteral("div")
};
const QVector<QString> Html::kBlockTags = { QStringLiteral("p"),
QStringLiteral("div") };
inline bool StrEquals(const QStringView &a, const QStringView &b)
{
return !a.compare(b, Qt::CaseInsensitive);
return !a.compare(b, Qt::CaseInsensitive);
}
QString Html::DocToHtml(const QTextDocument *doc)
{
QString html;
QXmlStreamWriter writer(&html);
QString html;
QXmlStreamWriter writer(&html);
//writer.setAutoFormatting(true);
//writer.setAutoFormatting(true);
for (auto it=doc->begin(); it!=doc->end(); it=it.next()) {
WriteBlock(&writer, it);
}
for (auto it = doc->begin(); it != doc->end(); it = it.next()) {
WriteBlock(&writer, it);
}
return html;
return html;
}
struct HtmlNode {
QString tag;
QTextCharFormat format;
QString tag;
QTextCharFormat format;
};
QTextCharFormat MergeHtmlFormats(const QVector<HtmlNode> &stack)
{
QTextCharFormat f;
QTextCharFormat f;
for (int i=0; i<stack.size(); i++) {
f.merge(stack.at(i).format);
}
for (int i = 0; i < stack.size(); i++) {
f.merge(stack.at(i).format);
}
return f;
return f;
}
void Html::HtmlToDoc(QTextDocument *doc, const QString &html)
{
// Empty doc
doc->clear();
bool inside_block = true;
// 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);
// 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);
QString wrapped = QStringLiteral("<html>").append(html).append("</html>");
QXmlStreamReader reader(wrapped);
QVector<HtmlNode> fmt_stack;
QVector<HtmlNode> fmt_stack;
QTextCharFormat default_fmt;
default_fmt.setFontWeight(QFont::Normal);
fmt_stack.append({QStringLiteral("html"), default_fmt});
QTextCharFormat default_fmt;
default_fmt.setFontWeight(QFont::Normal);
fmt_stack.append({ QStringLiteral("html"), default_fmt });
QTextCharFormat current_fmt;
QTextCharFormat current_fmt;
while (!reader.atEnd()) {
reader.readNext();
while (!reader.atEnd()) {
reader.readNext();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.tokenType() == QXmlStreamReader::StartElement) {
QString tag = reader.name().toString().toLower();
QString tag = reader.name().toString().toLower();
fmt_stack.append({ tag, ReadCharFormat(reader.attributes()) });
current_fmt = MergeHtmlFormats(fmt_stack);
fmt_stack.append({tag, ReadCharFormat(reader.attributes())});
current_fmt = MergeHtmlFormats(fmt_stack);
if (kBlockTags.contains(tag)) {
QTextBlockFormat block_fmt =
ReadBlockFormat(reader.attributes());
if (inside_block) {
c.setBlockFormat(block_fmt);
c.setBlockCharFormat(current_fmt);
} else {
c.insertBlock(block_fmt, current_fmt);
inside_block = true;
}
}
if (kBlockTags.contains(tag)) {
QTextBlockFormat block_fmt = ReadBlockFormat(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::Characters) {
} else if (reader.tokenType() == QXmlStreamReader::EndElement) {
QString tag = reader.name().toString().toLower();
QString characters = reader.text().toString();
c.insertText(characters, current_fmt);
for (int i = fmt_stack.size() - 1; i >= 0; i--) {
if (fmt_stack.at(i).tag == tag) {
fmt_stack.removeAt(i);
current_fmt = MergeHtmlFormats(fmt_stack);
} else if (reader.tokenType() == QXmlStreamReader::EndElement) {
if (kBlockTags.contains(tag)) {
inside_block = false;
}
break;
}
}
}
}
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 = MergeHtmlFormats(fmt_stack);
if (kBlockTags.contains(tag)) {
inside_block = false;
}
break;
}
}
}
}
if (reader.error()) {
qCritical() << "Failed to parse HTML:" << reader.errorString();
}
if (reader.error()) {
qCritical() << "Failed to parse HTML:" << reader.errorString();
}
}
void Html::WriteBlock(QXmlStreamWriter *writer, const QTextBlock &block)
{
writer->writeStartElement(QStringLiteral("p"));
writer->writeStartElement(QStringLiteral("p"));
const QTextBlockFormat &fmt = block.blockFormat();
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"));
}
}
// 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"));
}
// RTL support
if (block.textDirection() == Qt::RightToLeft) {
writer->writeAttribute(QStringLiteral("dir"), QStringLiteral("rtl"));
}
// Write CSS attributes
QString style;
// Write CSS attributes
QString style;
if (fmt.lineHeightType() != QTextBlockFormat::SingleHeight) {
WriteCSSProperty(&style, QStringLiteral("line-height"), QStringLiteral("%1%").arg(fmt.lineHeight()));
}
if (fmt.lineHeightType() != QTextBlockFormat::SingleHeight) {
WriteCSSProperty(&style, QStringLiteral("line-height"),
QStringLiteral("%1%").arg(fmt.lineHeight()));
}
WriteCharFormat(&style, block.charFormat());
WriteCharFormat(&style, block.charFormat());
if (!style.isEmpty()) {
writer->writeAttribute(QStringLiteral("style"), style);
}
if (!style.isEmpty()) {
writer->writeAttribute(QStringLiteral("style"), style);
}
auto it = block.begin();
auto it = block.begin();
if (it != block.end()) {
for (; it!=block.end(); it++) {
WriteFragment(writer, it.fragment());
}
}
if (it != block.end()) {
for (; it != block.end(); it++) {
WriteFragment(writer, it.fragment());
}
}
writer->writeEndElement(); // p
writer->writeEndElement(); // p
}
void Html::WriteFragment(QXmlStreamWriter *writer, const QTextFragment &fragment)
void Html::WriteFragment(QXmlStreamWriter *writer,
const QTextFragment &fragment)
{
const QTextCharFormat &fmt = fragment.charFormat();
const QTextCharFormat &fmt = fragment.charFormat();
writer->writeStartElement(QStringLiteral("span"));
writer->writeStartElement(QStringLiteral("span"));
// Write CSS attributes
QString style;
// Write CSS attributes
QString style;
WriteCharFormat(&style, fmt);
WriteCharFormat(&style, fmt);
if (!style.isEmpty()) {
writer->writeAttribute(QStringLiteral("style"), style);
}
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);
}
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
writer->writeEndElement(); // span
}
void Html::WriteCSSProperty(QString *style, const QString &key, const QStringList &values)
void Html::WriteCSSProperty(QString *style, const QString &key,
const QStringList &values)
{
QString value;
foreach (QString v, values) {
if (v.contains(' ')) {
v = QStringLiteral("'%1'").arg(v);
}
QString value;
foreach (QString v, values) {
if (v.contains(' ')) {
v = QStringLiteral("'%1'").arg(v);
}
AppendStringAutoSpace(&value, v);
}
AppendStringAutoSpace(&value, v);
}
AppendStringAutoSpace(style, QStringLiteral("%1: %2;").arg(key, value));
AppendStringAutoSpace(style, QStringLiteral("%1: %2;").arg(key, value));
}
void Html::WriteCharFormat(QString *style, const QTextCharFormat &fmt)
{
QStringList families = fmt.fontFamilies().toStringList();
if (!families.isEmpty()) {
WriteCSSProperty(style, QStringLiteral("font-family"), families.first());
}
QStringList families = fmt.fontFamilies().toStringList();
if (!families.isEmpty()) {
WriteCSSProperty(style, QStringLiteral("font-family"),
families.first());
}
if (fmt.hasProperty(QTextFormat::FontPointSize)) {
WriteCSSProperty(style, QStringLiteral("font-size"), QStringLiteral("%1pt").arg(QString::number(fmt.fontPointSize())));
}
if (fmt.hasProperty(QTextFormat::FontPointSize)) {
WriteCSSProperty(
style, QStringLiteral("font-size"),
QStringLiteral("%1pt").arg(QString::number(fmt.fontPointSize())));
}
if (fmt.hasProperty(QTextFormat::FontWeight)) {
WriteCSSProperty(style, QStringLiteral("font-weight"), QString::number(fmt.fontWeight() * 8));
}
if (fmt.hasProperty(QTextFormat::FontWeight)) {
WriteCSSProperty(style, QStringLiteral("font-weight"),
QString::number(fmt.fontWeight() * 8));
}
if (fmt.hasProperty(QTextFormat::FontItalic)) {
WriteCSSProperty(style, QStringLiteral("font-style"), fmt.fontItalic() ? QStringLiteral("italic") : QStringLiteral("normal"));
}
if (fmt.hasProperty(QTextFormat::FontItalic)) {
WriteCSSProperty(style, QStringLiteral("font-style"),
fmt.fontItalic() ? QStringLiteral("italic") :
QStringLiteral("normal"));
}
if (fmt.hasProperty(QTextFormat::FontStyleName)) {
WriteCSSProperty(style, QStringLiteral("-ove-font-style"), fmt.fontStyleName().toString());
}
if (fmt.hasProperty(QTextFormat::FontStyleName)) {
WriteCSSProperty(style, QStringLiteral("-ove-font-style"),
fmt.fontStyleName().toString());
}
QStringList deco;
QStringList deco;
if (fmt.fontUnderline()) {
deco.append(QStringLiteral("underline"));
}
if (fmt.fontUnderline()) {
deco.append(QStringLiteral("underline"));
}
if (fmt.fontStrikeOut()) {
deco.append(QStringLiteral("line-through"));
}
if (fmt.fontStrikeOut()) {
deco.append(QStringLiteral("line-through"));
}
if (fmt.fontOverline()) {
deco.append(QStringLiteral("overline"));
}
if (fmt.fontOverline()) {
deco.append(QStringLiteral("overline"));
}
if (!deco.isEmpty()) {
WriteCSSProperty(style, QStringLiteral("text-decoration"), deco);
}
if (!deco.isEmpty()) {
WriteCSSProperty(style, QStringLiteral("text-decoration"), deco);
}
if (fmt.foreground().style() != Qt::NoBrush) {
const QColor &color = fmt.foreground().color();
QString cs;
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()));
}
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()));
}
WriteCSSProperty(style, QStringLiteral("color"), cs);
}
WriteCSSProperty(style, QStringLiteral("color"), cs);
}
if (fmt.fontCapitalization() != QFont::MixedCase) {
if (fmt.fontCapitalization() == QFont::SmallCaps) {
WriteCSSProperty(style, QStringLiteral("font-variant"), QStringLiteral("small-caps"));
// TODO: Add others
}
}
if (fmt.fontCapitalization() != QFont::MixedCase) {
if (fmt.fontCapitalization() == QFont::SmallCaps) {
WriteCSSProperty(style, QStringLiteral("font-variant"),
QStringLiteral("small-caps"));
// TODO: Add others
}
}
if (fmt.fontLetterSpacing() != 0.0) {
WriteCSSProperty(style, QStringLiteral("letter-spacing"), QStringLiteral("%1%").arg(QString::number(fmt.fontLetterSpacing())));
}
if (fmt.fontLetterSpacing() != 0.0) {
WriteCSSProperty(style, QStringLiteral("letter-spacing"),
QStringLiteral("%1%").arg(
QString::number(fmt.fontLetterSpacing())));
}
if (fmt.fontStretch() != 0) {
WriteCSSProperty(style, QStringLiteral("font-stretch"), QStringLiteral("%1%").arg(QString::number(fmt.fontStretch())));
}
if (fmt.fontStretch() != 0) {
WriteCSSProperty(
style, QStringLiteral("font-stretch"),
QStringLiteral("%1%").arg(QString::number(fmt.fontStretch())));
}
}
QTextCharFormat Html::ReadCharFormat(const QXmlStreamAttributes &attributes)
{
QTextCharFormat fmt;
QTextCharFormat fmt;
foreach (const QXmlStreamAttribute &attr, attributes) {
if (StrEquals(attr.name(), QStringLiteral("style"))) {
auto css = GetCSSFromStyle(attr.value().toString());
foreach (const QXmlStreamAttribute &attr, attributes) {
if (StrEquals(attr.name(), QStringLiteral("style"))) {
auto css = GetCSSFromStyle(attr.value().toString());
for (auto it=css.begin(); it!=css.end(); it++) {
const QString &first_val = it.value().first();
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(StrEquals(first_val, QStringLiteral("italic")));
} else if (it.key() == QStringLiteral("text-decoration")) {
foreach (const QString &v, it.value()) {
if (StrEquals(v, QStringLiteral("underline"))) {
fmt.setFontUnderline(true);
} else if (StrEquals(v, QStringLiteral("line-through"))) {
fmt.setFontStrikeOut(true);
} else if (StrEquals(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.setRedF(rgba.at(0).toDouble());
c.setGreenF(rgba.at(1).toDouble());
c.setBlueF(rgba.at(2).toDouble());
c.setAlphaF(rgba.at(3).toDouble());
fmt.setForeground(c);
}
} else {
fmt.setForeground(QColor(first_val));
}
} else if (it.key() == QStringLiteral("font-variant")) {
if (StrEquals(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;
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(
StrEquals(first_val, QStringLiteral("italic")));
} else if (it.key() == QStringLiteral("text-decoration")) {
foreach (const QString &v, it.value()) {
if (StrEquals(v, QStringLiteral("underline"))) {
fmt.setFontUnderline(true);
} else if (StrEquals(v,
QStringLiteral("line-through"))) {
fmt.setFontStrikeOut(true);
} else if (StrEquals(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.setRedF(rgba.at(0).toDouble());
c.setGreenF(rgba.at(1).toDouble());
c.setBlueF(rgba.at(2).toDouble());
c.setAlphaF(rgba.at(3).toDouble());
fmt.setForeground(c);
}
} else {
fmt.setForeground(QColor(first_val));
}
} else if (it.key() == QStringLiteral("font-variant")) {
if (StrEquals(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::ReadBlockFormat(const QXmlStreamAttributes &attributes)
{
QTextBlockFormat block_fmt;
QTextBlockFormat block_fmt;
foreach (const QXmlStreamAttribute &attr, attributes) {
if (StrEquals(attr.name(), QStringLiteral("align"))) {
if (StrEquals(attr.value(), QStringLiteral("right"))) {
block_fmt.setAlignment(Qt::AlignRight);
} else if (StrEquals(attr.value(), QStringLiteral("center"))) {
block_fmt.setAlignment(Qt::AlignHCenter);
} else if (StrEquals(attr.value(), QStringLiteral("justify"))) {
block_fmt.setAlignment(Qt::AlignJustify);
}
} else if (StrEquals(attr.name(), QStringLiteral("dir"))) {
if (StrEquals(attr.value(), QStringLiteral("rtl"))) {
block_fmt.setLayoutDirection(Qt::RightToLeft);
}
} else if (StrEquals(attr.name(), QStringLiteral("style"))) {
auto css = GetCSSFromStyle(attr.value().toString());
foreach (const QXmlStreamAttribute &attr, attributes) {
if (StrEquals(attr.name(), QStringLiteral("align"))) {
if (StrEquals(attr.value(), QStringLiteral("right"))) {
block_fmt.setAlignment(Qt::AlignRight);
} else if (StrEquals(attr.value(), QStringLiteral("center"))) {
block_fmt.setAlignment(Qt::AlignHCenter);
} else if (StrEquals(attr.value(), QStringLiteral("justify"))) {
block_fmt.setAlignment(Qt::AlignJustify);
}
} else if (StrEquals(attr.name(), QStringLiteral("dir"))) {
if (StrEquals(attr.value(), QStringLiteral("rtl"))) {
block_fmt.setLayoutDirection(Qt::RightToLeft);
}
} else if (StrEquals(attr.name(), QStringLiteral("style"))) {
auto css = GetCSSFromStyle(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);
}
}
}
}
}
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;
return block_fmt;
}
void Html::AppendStringAutoSpace(QString *s, const QString &append)
{
if (!s->isEmpty()) {
s->append(QChar(' '));
}
if (!s->isEmpty()) {
s->append(QChar(' '));
}
s->append(append);
s->append(append);
}
QMap<QString, QStringList> Html::GetCSSFromStyle(const QString &s)
{
QMap<QString, QStringList> map;
QMap<QString, QStringList> map;
QStringList list = s.split(QChar(';'));
QStringList list = s.split(QChar(';'));
foreach (const QString &a, list) {
QStringList kv = a.split(QChar(':'));
foreach (const QString &a, list) {
QStringList kv = a.split(QChar(':'));
if (kv.size() != 2) {
continue;
}
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);
// 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 (!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);
}
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());
}
// 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;
}
map[kv.at(0).trimmed().toLower()] = values;
}
return map;
return map;
}
}
+22 -17
View File
@@ -6,7 +6,8 @@
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
namespace olive {
namespace olive
{
/**
* @brief Functions for converting HTML to QTextDocument and vice versa
@@ -26,33 +27,37 @@ namespace olive {
*/
class Html {
public:
static QString DocToHtml(const QTextDocument *doc);
static QString DocToHtml(const QTextDocument *doc);
static void HtmlToDoc(QTextDocument *doc, const QString &html);
static void HtmlToDoc(QTextDocument *doc, const QString &html);
private:
static void WriteBlock(QXmlStreamWriter *writer, const QTextBlock &block);
static void WriteBlock(QXmlStreamWriter *writer, const QTextBlock &block);
static void WriteFragment(QXmlStreamWriter *writer, const QTextFragment &fragment);
static void WriteFragment(QXmlStreamWriter *writer,
const QTextFragment &fragment);
static void WriteCSSProperty(QString *style, const QString &key, const QStringList &value);
static void WriteCSSProperty(QString *style, const QString &key, const QString &value)
{
WriteCSSProperty(style, key, QStringList({value}));
}
static void WriteCSSProperty(QString *style, const QString &key,
const QStringList &value);
static void WriteCSSProperty(QString *style, const QString &key,
const QString &value)
{
WriteCSSProperty(style, key, QStringList({ value }));
}
static void WriteCharFormat(QString *style, const QTextCharFormat &fmt);
static void WriteCharFormat(QString *style, const QTextCharFormat &fmt);
static QTextCharFormat ReadCharFormat(const QXmlStreamAttributes &attributes);
static QTextCharFormat
ReadCharFormat(const QXmlStreamAttributes &attributes);
static QTextBlockFormat ReadBlockFormat(const QXmlStreamAttributes &attributes);
static QTextBlockFormat
ReadBlockFormat(const QXmlStreamAttributes &attributes);
static void AppendStringAutoSpace(QString *s, const QString &append);
static void AppendStringAutoSpace(QString *s, const QString &append);
static QMap<QString, QStringList> GetCSSFromStyle(const QString &s);
static const QVector<QString> kBlockTags;
static QMap<QString, QStringList> GetCSSFromStyle(const QString &s);
static const QVector<QString> kBlockTags;
};
}
+9 -8
View File
@@ -2,29 +2,30 @@
#include <QMutex>
namespace olive {
namespace olive
{
uint64_t job_time_index = 0;
QMutex job_time_mutex;
JobTime::JobTime()
{
Acquire();
Acquire();
}
void JobTime::Acquire()
{
job_time_mutex.lock();
job_time_mutex.lock();
value_ = job_time_index;
job_time_index++;
value_ = job_time_index;
job_time_index++;
job_time_mutex.unlock();
job_time_mutex.unlock();
}
}
QDebug operator<<(QDebug debug, const olive::JobTime& r)
QDebug operator<<(QDebug debug, const olive::JobTime &r)
{
return debug.space() << r.value();
return debug.space() << r.value();
}
+35 -36
View File
@@ -4,58 +4,57 @@
#include <QDebug>
#include <stdint.h>
namespace olive {
class JobTime
namespace olive
{
class JobTime {
public:
JobTime();
JobTime();
void Acquire();
void Acquire();
uint64_t value() const
{
return value_;
}
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_;
}
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_;
uint64_t value_;
};
}
QDebug operator<<(QDebug debug, const olive::JobTime& r);
QDebug operator<<(QDebug debug, const olive::JobTime &r);
Q_DECLARE_METATYPE(olive::JobTime)
+7 -6
View File
@@ -21,20 +21,21 @@
#ifndef LERP_H
#define LERP_H
template<typename T>
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);
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);
template <typename T> T lerp(T a, T b, float t)
{
return (a * (1.0f - t)) + (b * t);
}
#endif // LERP_H
+249 -245
View File
@@ -31,7 +31,8 @@
#include "common/define.h"
namespace olive {
namespace olive
{
/**
* @brief MemoryPool base class
@@ -46,386 +47,389 @@ namespace olive {
* `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
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;
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);
}
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();
}
virtual ~MemoryPool()
{
Clear();
clear_timer_->deleteLater();
}
DISABLE_COPY_MOVE(MemoryPool)
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();
}
void Clear()
{
qDeleteAll(arenas_);
arenas_.clear();
}
/**
/**
* @brief Returns whether any arenas are successfully allocated
*/
inline bool IsAllocated() const
{
return !arenas_.empty();
}
inline bool IsAllocated() const
{
return !arenas_.empty();
}
/**
/**
* @brief Returns current number of allocated arenas
*/
inline int GetArenaCount() const
{
return arenas_.size();
}
inline int GetArenaCount() const
{
return arenas_.size();
}
class Arena;
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:
/**
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();
}
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();
}
~Element()
{
release();
}
DISABLE_COPY_MOVE(Element)
DISABLE_COPY_MOVE(Element)
/**
/**
* @brief Access data represented in the pool
*/
inline uint8_t* data() const
{
return data_;
}
inline uint8_t *data() const
{
return data_;
}
inline const int64_t& timestamp() const
{
return timestamp_;
}
inline const int64_t &timestamp() const
{
return timestamp_;
}
inline void set_timestamp(const int64_t& timestamp)
{
timestamp_ = 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();
}
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_;
}
inline const int64_t &last_accessed() const
{
return accessed_;
}
void release()
{
if (data_) {
parent_->Release(this);
data_ = nullptr;
}
}
void release()
{
if (data_) {
parent_->Release(this);
data_ = nullptr;
}
}
private:
Arena* parent_;
private:
Arena *parent_;
uint8_t* data_;
uint8_t *data_;
int64_t timestamp_;
int64_t timestamp_;
int64_t accessed_;
int64_t accessed_;
};
};
using ElementPtr = std::shared_ptr<Element>;
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();
}
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();
}
~Arena()
{
std::list<Element *> copy = lent_elements_;
foreach (Element *e, copy) {
e->release();
}
delete [] data_;
}
delete[] data_;
}
DISABLE_COPY_MOVE(Arena)
DISABLE_COPY_MOVE(Arena)
/**
/**
* @brief Returns an element if there is free memory to do so
*/
ElementPtr Get()
{
QMutexLocker locker(&lock_);
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);
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());
ElementPtr e = std::make_shared<Element>(
this,
reinterpret_cast<uint8_t *>(data_ + i * element_sz_));
lent_elements_.push_back(e.get());
return e;
}
}
return e;
}
}
return nullptr;
}
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_);
void Release(Element *e)
{
QMutexLocker locker(&lock_);
quintptr diff = reinterpret_cast<quintptr>(e->data()) -
reinterpret_cast<quintptr>(data_);
int index = diff / element_sz_;
int index = diff / element_sz_;
available_.replace(index, true);
available_.replace(index, true);
lent_elements_.remove(e);
lent_elements_.remove(e);
if (lent_elements_.empty()) {
empty_time_ = QDateTime::currentMSecsSinceEpoch();
}
}
if (lent_elements_.empty()) {
empty_time_ = QDateTime::currentMSecsSinceEpoch();
}
}
int GetUsageCount()
{
QMutexLocker locker(&lock_);
return lent_elements_.size();
}
int GetUsageCount()
{
QMutexLocker locker(&lock_);
return lent_elements_.size();
}
bool Allocate(size_t ele_sz, size_t nb_elements)
{
if (IsAllocated()) {
return true;
}
bool Allocate(size_t ele_sz, size_t nb_elements)
{
if (IsAllocated()) {
return true;
}
element_sz_ = ele_sz;
element_sz_ = ele_sz;
allocated_sz_ = element_sz_ * nb_elements;
allocated_sz_ = element_sz_ * nb_elements;
if ((data_ = new uint8_t[allocated_sz_])) {
available_.resize(nb_elements);
available_.fill(true);
if ((data_ = new uint8_t[allocated_sz_])) {
available_.resize(nb_elements);
available_.fill(true);
return true;
} else {
available_.clear();
return true;
} else {
available_.clear();
return false;
}
}
return false;
}
}
inline int GetElementCount() const
{
return available_.size();
}
inline int GetElementCount() const
{
return available_.size();
}
inline bool IsAllocated() const
{
return data_;
}
inline bool IsAllocated() const
{
return data_;
}
inline qint64 GetTimeArenaWasMadeEmpty()
{
QMutexLocker locker(&lock_);
return empty_time_;
}
inline qint64 GetTimeArenaWasMadeEmpty()
{
QMutexLocker locker(&lock_);
return empty_time_;
}
private:
MemoryPool* parent_;
private:
MemoryPool *parent_;
uint8_t* data_;
uint8_t *data_;
size_t allocated_sz_;
size_t allocated_sz_;
QVector<bool> available_;
QVector<bool> available_;
QMutex lock_;
QMutex lock_;
size_t element_sz_;
size_t element_sz_;
std::list<Element*> lent_elements_;
std::list<Element *> lent_elements_;
qint64 empty_time_;
qint64 empty_time_;
};
};
/**
/**
* @brief Retrieves an element from an available arena
*/
ElementPtr Get()
{
QMutexLocker locker(&lock_);
ElementPtr Get()
{
QMutexLocker locker(&lock_);
// Attempt to get an element from an arena
foreach (Arena* a, arenas_) {
ElementPtr e = a->Get();
// Attempt to get an element from an arena
foreach (Arena *a, arenas_) {
ElementPtr e = a->Get();
if (e) {
return e;
}
}
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...";
}
// 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();
size_t ele_sz = GetElementSize();
if (!ele_sz) {
qCritical() << "Failed to create arena, element size was 0";
return nullptr;
}
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;
}
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;
}
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();
}
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);
}
virtual size_t GetElementSize()
{
return sizeof(uint8_t);
}
private:
int element_count_;
int element_count_;
std::list<Arena*> arenas_;
std::list<Arena *> arenas_;
QMutex lock_;
QMutex lock_;
QTimer *clear_timer_;
QTimer *clear_timer_;
static const qint64 kMaxEmptyArenaLife = 5000;
static const qint64 kMaxEmptyArenaLife = 5000;
private slots:
void ClearEmptyArenas()
{
QMutexLocker locker(&lock_);
void ClearEmptyArenas()
{
QMutexLocker locker(&lock_);
const qint64 min_time = QDateTime::currentMSecsSinceEpoch() - kMaxEmptyArenaLife;
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++;
}
}
}
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++;
}
}
}
};
}
+19 -18
View File
@@ -20,28 +20,29 @@
#include "ocioutils.h"
namespace olive {
namespace olive
{
OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(PixelFormat format)
{
switch (format) {
case PixelFormat::U8:
return OCIO::BIT_DEPTH_UINT8;
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;
}
switch (format) {
case PixelFormat::U8:
return OCIO::BIT_DEPTH_UINT8;
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;
return OCIO::BIT_DEPTH_UNKNOWN;
}
}
+4 -4
View File
@@ -26,12 +26,12 @@ namespace OCIO = OCIO_NAMESPACE;
#include "render/videoparams.h"
namespace olive {
class OCIOUtils
namespace olive
{
class OCIOUtils {
public:
static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(PixelFormat format);
static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(PixelFormat format);
};
}
+37 -41
View File
@@ -22,62 +22,58 @@
#include <QDebug>
namespace olive {
void OIIOUtils::FrameToBuffer(const Frame* frame, OIIO::ImageBuf *buf)
namespace olive
{
buf->set_pixels(OIIO::ROI(),
buf->spec().format,
frame->const_data(),
OIIO::AutoStride,
frame->linesize_bytes());
void OIIOUtils::FrameToBuffer(const Frame *frame, OIIO::ImageBuf *buf)
{
buf->set_pixels(OIIO::ROI(), buf->spec().format, frame->const_data(),
OIIO::AutoStride, frame->linesize_bytes());
}
void OIIOUtils::BufferToFrame(OIIO::ImageBuf *buf, Frame* frame)
void OIIOUtils::BufferToFrame(OIIO::ImageBuf *buf, Frame *frame)
{
buf->get_pixels(OIIO::ROI(),
buf->spec().format,
frame->data(),
OIIO::AutoStride,
frame->linesize_bytes());
buf->get_pixels(OIIO::ROI(), buf->spec().format, frame->data(),
OIIO::AutoStride, frame->linesize_bytes());
}
rational OIIOUtils::GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec)
{
return rational::fromDouble(spec.get_float_attribute("PixelAspectRatio", 1));
return rational::fromDouble(
spec.get_float_attribute("PixelAspectRatio", 1));
}
PixelFormat OIIOUtils::GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type)
{
switch (type) {
case OIIO::TypeDesc::UNKNOWN:
case OIIO::TypeDesc::NONE:
break;
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::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;
}
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;
return PixelFormat::INVALID;
}
}
+24 -23
View File
@@ -27,37 +27,38 @@
#include "codec/frame.h"
#include "render/videoparams.h"
namespace olive {
namespace olive
{
class OIIOUtils {
public:
static OIIO::TypeDesc::BASETYPE GetOIIOBaseTypeFromFormat(PixelFormat format)
{
switch (format) {
case PixelFormat::U8:
return OIIO::TypeDesc::UINT8;
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;
}
static OIIO::TypeDesc::BASETYPE
GetOIIOBaseTypeFromFormat(PixelFormat format)
{
switch (format) {
case PixelFormat::U8:
return OIIO::TypeDesc::UINT8;
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;
}
return OIIO::TypeDesc::UNKNOWN;
}
static void FrameToBuffer(const Frame *frame, OIIO::ImageBuf* buf);
static void FrameToBuffer(const Frame *frame, OIIO::ImageBuf *buf);
static void BufferToFrame(OIIO::ImageBuf* buf, Frame* frame);
static void BufferToFrame(OIIO::ImageBuf *buf, Frame *frame);
static PixelFormat GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type);
static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec& spec);
static PixelFormat GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type);
static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec);
};
}
+16 -15
View File
@@ -25,30 +25,31 @@
#include "common/define.h"
namespace olive {
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++;
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return 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);
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x - (x >> 1);
return x - (x >> 1);
}
}
+125 -114
View File
@@ -22,192 +22,203 @@
#include <QDebug>
namespace olive {
namespace olive
{
int QtUtils::QFontMetricsWidth(QFontMetrics fm, const QString& s) {
int QtUtils::QFontMetricsWidth(QFontMetrics fm, const QString &s)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
return fm.width(s);
return fm.width(s);
#else
return fm.horizontalAdvance(s);
return fm.horizontalAdvance(s);
#endif
}
QFrame *QtUtils::CreateHorizontalLine()
{
QFrame* horizontal_line = new QFrame();
horizontal_line->setFrameShape(QFrame::HLine);
horizontal_line->setFrameShadow(QFrame::Sunken);
return horizontal_line;
QFrame *horizontal_line = new QFrame();
horizontal_line->setFrameShape(QFrame::HLine);
horizontal_line->setFrameShadow(QFrame::Sunken);
return horizontal_line;
}
QFrame *QtUtils::CreateVerticalLine()
{
QFrame *l = CreateHorizontalLine();
l->setFrameShape(QFrame::VLine);
return l;
QFrame *l = CreateHorizontalLine();
l->setFrameShape(QFrame::VLine);
return l;
}
int QtUtils::MsgBox(QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &message, QMessageBox::StandardButtons buttons)
int QtUtils::MsgBox(QWidget *parent, QMessageBox::Icon icon,
const QString &title, const QString &message,
QMessageBox::StandardButtons buttons)
{
QMessageBox b(parent);
b.setIcon(icon);
b.setWindowModality(Qt::WindowModal);
b.setWindowTitle(title);
b.setText(message);
QMessageBox b(parent);
b.setIcon(icon);
b.setWindowModality(Qt::WindowModal);
b.setWindowTitle(title);
b.setText(message);
uint mask = QMessageBox::FirstButton;
while (mask <= QMessageBox::LastButton) {
uint sb = buttons & mask;
if (sb) {
b.addButton(static_cast<QMessageBox::StandardButton>(sb));
}
mask <<= 1;
}
uint mask = QMessageBox::FirstButton;
while (mask <= QMessageBox::LastButton) {
uint sb = buttons & mask;
if (sb) {
b.addButton(static_cast<QMessageBox::StandardButton>(sb));
}
mask <<= 1;
}
return b.exec();
return b.exec();
}
QDateTime QtUtils::GetCreationDate(const QFileInfo &info)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
return info.created();
return info.created();
#else
QDateTime t = info.birthTime();
if (!t.isValid()) {
t = info.metadataChangeTime();
}
return t;
QDateTime t = info.birthTime();
if (!t.isValid()) {
t = info.metadataChangeTime();
}
return t;
#endif
}
QString QtUtils::GetFormattedDateTime(const QDateTime &dt)
{
return dt.toString(Qt::TextDate);
return dt.toString(Qt::TextDate);
}
QStringList QtUtils::WordWrapString(const QString &s, const QFontMetrics &fm, int bounding_width)
QStringList QtUtils::WordWrapString(const QString &s, const QFontMetrics &fm,
int bounding_width)
{
QStringList list;
QStringList list;
QStringList lines = s.split('\n');
QStringList lines = s.split('\n');
// Iterate every line
for (int i=0; i<lines.size(); i++) {
QString this_line = lines.at(i);
// Iterate every line
for (int i = 0; i < lines.size(); i++) {
QString this_line = lines.at(i);
while (this_line.size() > 1 && QFontMetricsWidth(fm, this_line) >= bounding_width) {
int old_size = this_line.size();
int hard_break = -1;
while (this_line.size() > 1 &&
QFontMetricsWidth(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);
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 (QFontMetricsWidth(fm, this_line.left(j)) < bounding_width) {
if (!char_test.isSpace()) {
j++;
}
if (char_test.isSpace() || char_test == '-') {
if (QFontMetricsWidth(fm, this_line.left(j)) <
bounding_width) {
if (!char_test.isSpace()) {
j++;
}
QString chopped = this_line.left(j);
QString chopped = this_line.left(j);
list.append(chopped);
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 && QFontMetricsWidth(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;
}
}
while (j < this_line.size() &&
this_line.at(j).isSpace()) {
j++;
}
this_line.remove(0, j);
break;
}
} else if (hard_break == -1 &&
QFontMetricsWidth(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 (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);
}
}
if (!this_line.isEmpty()) {
list.append(this_line);
}
}
return list;
return list;
}
Qt::KeyboardModifiers QtUtils::FlipControlAndShiftModifiers(Qt::KeyboardModifiers e)
Qt::KeyboardModifiers
QtUtils::FlipControlAndShiftModifiers(Qt::KeyboardModifiers e)
{
if (e & Qt::ControlModifier & Qt::ShiftModifier) {
return 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;
}
if (e & Qt::ShiftModifier) {
e |= Qt::ControlModifier;
e &= ~Qt::ShiftModifier;
} else if (e & Qt::ControlModifier) {
e |= Qt::ShiftModifier;
e &= ~Qt::ControlModifier;
}
return e;
return e;
}
void QtUtils::SetComboBoxData(QComboBox *cb, int data)
{
for (int i=0; i<cb->count(); i++) {
if (cb->itemData(i).toInt() == data) {
cb->setCurrentIndex(i);
break;
}
}
for (int i = 0; i < cb->count(); i++) {
if (cb->itemData(i).toInt() == data) {
cb->setCurrentIndex(i);
break;
}
}
}
void QtUtils::SetComboBoxData(QComboBox *cb, const QString &data)
{
for (int i=0; i<cb->count(); i++) {
if (cb->itemData(i).toString() == data) {
cb->setCurrentIndex(i);
break;
}
}
for (int i = 0; i < cb->count(); i++) {
if (cb->itemData(i).toString() == data) {
cb->setCurrentIndex(i);
break;
}
}
}
QColor QtUtils::toQColor(const core::Color &i)
{
QColor c;
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));
// 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;
return c;
}
namespace core {
namespace core
{
uint qHash(const core::rational &r, uint seed)
{
return ::qHash(r.toDouble(), seed);
return ::qHash(r.toDouble(), seed);
}
uint qHash(const core::TimeRange &r, uint seed)
{
return qHash(r.in(), seed) ^ qHash(r.out(), seed);
return qHash(r.in(), seed) ^ qHash(r.out(), seed);
}
}
}
+43 -40
View File
@@ -29,76 +29,79 @@
#include <QFrame>
#include <QMessageBox>
namespace olive {
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 QFontMetricsWidth(QFontMetrics fm, const QString& s);
static int QFontMetricsWidth(QFontMetrics fm, const QString &s);
static QFrame* CreateHorizontalLine();
static QFrame *CreateHorizontalLine();
static QFrame* CreateVerticalLine();
static QFrame *CreateVerticalLine();
static int MsgBox(QWidget *parent, QMessageBox::Icon icon, const QString& title, const QString& message, QMessageBox::StandardButtons buttons = QMessageBox::Ok);
static int MsgBox(QWidget *parent, QMessageBox::Icon icon,
const QString &title, const QString &message,
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
static QDateTime GetCreationDate(const QFileInfo &info);
static QDateTime GetCreationDate(const QFileInfo &info);
static QString GetFormattedDateTime(const QDateTime &dt);
static QString GetFormattedDateTime(const QDateTime &dt);
static QStringList WordWrapString(const QString &s, const QFontMetrics &fm, int bounding_width);
static QStringList WordWrapString(const QString &s, const QFontMetrics &fm,
int bounding_width);
static Qt::KeyboardModifiers FlipControlAndShiftModifiers(Qt::KeyboardModifiers e);
static Qt::KeyboardModifiers
FlipControlAndShiftModifiers(Qt::KeyboardModifiers e);
static void SetComboBoxData(QComboBox *cb, int data);
static void SetComboBoxData(QComboBox *cb, const QString &data);
static void SetComboBoxData(QComboBox *cb, int data);
static void SetComboBoxData(QComboBox *cb, const QString &data);
template <typename T>
static T *GetParentOfType(const QObject *child)
{
QObject *t = child->parent();
template <typename T> static T *GetParentOfType(const QObject *child)
{
QObject *t = child->parent();
while (t) {
if (T *p = dynamic_cast<T*>(t)) {
return p;
}
t = t->parent();
}
while (t) {
if (T *p = dynamic_cast<T *>(t)) {
return p;
}
t = t->parent();
}
return nullptr;
}
return nullptr;
}
static QColor toQColor(const core::Color &c);
static QColor toQColor(const core::Color &c);
/**
/**
* @brief Convert a pointer to a value that can be sent between NodeParams
*/
static QVariant PtrToValue(void* ptr)
{
return reinterpret_cast<quintptr>(ptr);
}
static QVariant PtrToValue(void *ptr)
{
return reinterpret_cast<quintptr>(ptr);
}
/**
/**
* @brief Convert a NodeParam value to a pointer of any kind
*/
template<class T>
static T* ValueToPtr(const QVariant &ptr)
{
return reinterpret_cast<T*>(ptr.value<quintptr>());
}
template <class T> static T *ValueToPtr(const QVariant &ptr)
{
return reinterpret_cast<T *>(ptr.value<quintptr>());
}
};
namespace core {
namespace core
{
uint qHash(const core::rational& r, uint seed = 0);
uint qHash(const core::TimeRange& r, uint seed = 0);
uint qHash(const core::rational &r, uint seed = 0);
uint qHash(const core::TimeRange &r, uint seed = 0);
}
+2 -3
View File
@@ -21,10 +21,9 @@
#ifndef RANGE_H
#define RANGE_H
template <typename T>
bool InRange(T a, T b, T range)
template <typename T> bool InRange(T a, T b, T range)
{
return (a >= b - range && a <= b + range);
return (a >= b - range && a <= b + range);
}
#endif // RANGE_H
+54 -52
View File
@@ -24,69 +24,71 @@
#include <QMessageBox>
#include <QRegularExpression>
namespace olive {
double GetFloatRatioFromUser(QWidget* parent,
const QString& title,
bool* ok_in)
namespace olive
{
QString s;
forever {
bool ok;
double GetFloatRatioFromUser(QWidget *parent, const QString &title, bool *ok_in)
{
QString s;
s = QInputDialog::getText(parent,
title,
QCoreApplication::translate("RatioDialog", "Enter custom ratio (e.g. \"4:3\", \"16/9\", etc.):"),
QLineEdit::Normal,
s,
&ok);
forever
{
bool ok;
if (!ok) {
// User cancelled dialog, do nothing
if (ok_in) {
*ok_in = false;
}
return qSNaN();
}
s = QInputDialog::getText(
parent, title,
QCoreApplication::translate(
"RatioDialog",
"Enter custom ratio (e.g. \"4:3\", \"16/9\", etc.):"),
QLineEdit::Normal, s, &ok);
QStringList ratio_components = s.split(QRegularExpression(QStringLiteral(":|;|\\/")));
if (!ok) {
// User cancelled dialog, do nothing
if (ok_in) {
*ok_in = false;
}
return qSNaN();
}
if (ratio_components.size() == 1) {
bool float_ok;
QStringList ratio_components =
s.split(QRegularExpression(QStringLiteral(":|;|\\/")));
double flt = ratio_components.at(0).toDouble(&float_ok);
if (ratio_components.size() == 1) {
bool float_ok;
if (float_ok && flt > 0) {
if (ok_in) {
*ok_in = true;
}
return flt;
}
} else if (ratio_components.size() == 2) {
bool numer_ok, denom_ok;
double flt = ratio_components.at(0).toDouble(&float_ok);
double num = ratio_components.at(0).toDouble(&numer_ok);
double den = ratio_components.at(1).toDouble(&denom_ok);
if (float_ok && flt > 0) {
if (ok_in) {
*ok_in = true;
}
return flt;
}
} else if (ratio_components.size() == 2) {
bool numer_ok, denom_ok;
if (numer_ok
&& denom_ok
&& num > 0
&& den > 0) {
// Exit loop and set this ratio
if (ok_in) {
*ok_in = true;
}
return num / den;
}
}
double num = ratio_components.at(0).toDouble(&numer_ok);
double den = ratio_components.at(1).toDouble(&denom_ok);
QMessageBox::warning(parent,
QCoreApplication::translate("RatioDialog", "Invalid custom ratio"),
QCoreApplication::translate("RatioDialog", "Failed to parse \"%1\" into an aspect ratio. Please format a "
"rational fraction with a ':' or a '/' separator.").arg(s),
QMessageBox::Ok);
}
if (numer_ok && denom_ok && num > 0 && den > 0) {
// Exit loop and set this ratio
if (ok_in) {
*ok_in = true;
}
return num / den;
}
}
QMessageBox::warning(
parent,
QCoreApplication::translate("RatioDialog", "Invalid custom ratio"),
QCoreApplication::translate(
"RatioDialog",
"Failed to parse \"%1\" into an aspect ratio. Please format a "
"rational fraction with a ':' or a '/' separator.")
.arg(s),
QMessageBox::Ok);
}
}
}
+4 -4
View File
@@ -23,11 +23,11 @@
#include <QInputDialog>
namespace olive {
namespace olive
{
double GetFloatRatioFromUser(QWidget* parent,
const QString& title,
bool* ok_in);
double GetFloatRatioFromUser(QWidget *parent, const QString &title,
bool *ok_in);
}
+10 -13
View File
@@ -4,24 +4,21 @@
#include <QMap>
#include <QMutex>
template <typename K, typename V>
class ThreadSafeMap
{
template <typename K, typename V> class ThreadSafeMap {
public:
ThreadSafeMap() = default;
ThreadSafeMap() = default;
void insert(K key, V value)
{
mutex_.lock();
map_.insert(key, value);
mutex_.unlock();
}
void insert(K key, V value)
{
mutex_.lock();
map_.insert(key, value);
mutex_.unlock();
}
private:
QMutex mutex_;
QMap<K, V> map_;
QMutex mutex_;
QMap<K, V> map_;
};
#endif // THREADSAFEMAP_H
+5 -3
View File
@@ -6,10 +6,12 @@
#include "common/define.h"
namespace olive {
namespace olive
{
inline QString ToHex(quint64 t) {
return QStringLiteral("%1").arg(t, 0, 16);
inline QString ToHex(quint64 t)
{
return QStringLiteral("%1").arg(t, 0, 16);
}
}
+2 -3
View File
@@ -21,10 +21,9 @@
#ifndef UTIL_H
#define UTIL_H
template <typename T>
inline T mid(T a, T b)
template <typename T> inline T mid(T a, T b)
{
return (a + b) * 0.5;
return (a + b) * 0.5;
}
#endif // UTIL_H
+13 -12
View File
@@ -23,23 +23,24 @@
#include "node/block/block.h"
#include "node/factory.h"
namespace olive {
namespace olive
{
bool XMLReadNextStartElement(QXmlStreamReader *reader, CancelAtom *cancel_atom)
{
QXmlStreamReader::TokenType token;
QXmlStreamReader::TokenType token;
while ((token = reader->readNext()) != QXmlStreamReader::Invalid
&& token != QXmlStreamReader::EndDocument
&& (!cancel_atom || !cancel_atom->IsCancelled())) {
if (reader->isEndElement()) {
return false;
} else if (reader->isStartElement()) {
return true;
}
}
while ((token = reader->readNext()) != QXmlStreamReader::Invalid &&
token != QXmlStreamReader::EndDocument &&
(!cancel_atom || !cancel_atom->IsCancelled())) {
if (reader->isEndElement()) {
return false;
} else if (reader->isStartElement()) {
return true;
}
}
return false;
return false;
}
}
+5 -3
View File
@@ -27,7 +27,8 @@
#include "render/cancelatom.h"
#include "undo/undocommand.h"
namespace olive {
namespace olive
{
class Block;
class Node;
@@ -35,7 +36,7 @@ class NodeInput;
class NodeGroup;
#define XMLAttributeLoop(reader, item) \
foreach (const QXmlStreamAttribute& item, reader->attributes())
foreach (const QXmlStreamAttribute &item, reader->attributes())
/**
* @brief Workaround for QXmlStreamReader::readNextStartElement not detecting the end of a document
@@ -46,7 +47,8 @@ class NodeGroup;
*
* See also: https://stackoverflow.com/questions/46346450/qt-qxmlstreamreader-always-returns-premature-end-of-document-error
*/
bool XMLReadNextStartElement(QXmlStreamReader* reader, CancelAtom *cancel_atom = nullptr);
bool XMLReadNextStartElement(QXmlStreamReader *reader,
CancelAtom *cancel_atom = nullptr);
}