Physical split: app/{audio,cli,codec,common,config,node,pluginSupport,
render,task,timeline,undo,tool,shaders} plus coreengine, version and
ui/icons+colorcoding move to a new top-level engine/ tree, built as
liboakengine.so (shared). The render backends (oakgl/oakvulkan) move
with it and link the engine library instead of embedding a static
render-core subset (libolive-rendercore is gone).
- oak-render-worker now links liboakengine instead of the whole
libolive-editor object set: 336MB -> 2.9MB, no Qt Widgets UI
- the editor links liboakengine for the engine and keeps only UI
objects in libolive-editor
- install/packaging: GNUInstallDirs libdir on Linux, bundle copy on
macOS, oakengine.dll staged for NSIS, AppImage validation entry
- fix backend lookup for the new layout: DynamicRenderer searched
../app but backends now live in engine/; a stale pre-split liboakgl
in the build tree got dlopened instead, re-initialized and later
destroyed the interposed engine statics (full-suite segfault at
DialogSequenceParameterTab, found via gdb watchpoint)
185 lines
6.3 KiB
C++
185 lines
6.3 KiB
C++
/***
|
|
|
|
Olive - Non-Linear Video Editor
|
|
Copyright (C) 2022 Olive Team
|
|
Modifications Copyright (C) 2025 mikesolar
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
#include "subtitleparams.h"
|
|
|
|
#include <QCoreApplication>
|
|
|
|
#include "common/xmlutils.h"
|
|
|
|
namespace olive
|
|
{
|
|
|
|
QString SubtitleParams::generate_ass_header()
|
|
{
|
|
// NOTE: We'll probably implement more customization as we support ASS better. Right now, we only
|
|
// natively support SRT and only make this header because FFmpeg requires it.
|
|
static const int k_ass_default_play_res_x = 384;
|
|
static const int k_ass_default_play_res_y = 288;
|
|
static const QString k_ass_default_font = QStringLiteral("Arial");
|
|
static const int k_ass_default_font_size = 16;
|
|
static const int k_ass_default_primary_color = 0xFFFFFF; // White
|
|
static const int k_ass_default_secondary_color = 0xFFFFFF; // White
|
|
static const int k_ass_default_outline_color = 0x000000; // Black
|
|
static const int k_ass_default_back_color = 0x000000; // Black
|
|
static const int k_ass_bold = 0;
|
|
static const int k_ass_italic = 0;
|
|
static const int k_ass_underline = 0;
|
|
static const int k_ass_strike = 0;
|
|
static const int k_ass_border_style = 1;
|
|
static const int k_ass_alignment = 2;
|
|
|
|
QString ass_code;
|
|
|
|
// Header info
|
|
ass_code.append(QStringLiteral("[Script Info]\r\n"));
|
|
ass_code.append(QStringLiteral("; Script generated by %1 %2\r\n")
|
|
.arg(QCoreApplication::applicationName(),
|
|
QCoreApplication::applicationVersion()));
|
|
ass_code.append(QStringLiteral("ScriptType: v4.00+\r\n"));
|
|
ass_code.append(QStringLiteral("PlayResX: %1\r\n")
|
|
.arg(QString::number(k_ass_default_play_res_x)));
|
|
ass_code.append(QStringLiteral("PlayResY: %1\r\n")
|
|
.arg(QString::number(k_ass_default_play_res_y)));
|
|
ass_code.append(QStringLiteral("ScaledBorderAndShadow: yes\r\n"));
|
|
ass_code.append(QStringLiteral("\r\n"));
|
|
|
|
// ASSv4 header
|
|
ass_code.append(QStringLiteral("[V4+ Styles]\r\n"));
|
|
ass_code.append(QStringLiteral("Format: Name, "));
|
|
ass_code.append(QStringLiteral("Fontname, Fontsize, "));
|
|
ass_code.append(QStringLiteral(
|
|
"PrimaryColour, SecondaryColour, OutlineColour, BackColour, "));
|
|
ass_code.append(QStringLiteral("Bold, Italic, Underline, StrikeOut, "));
|
|
ass_code.append(QStringLiteral("ScaleX, ScaleY, "));
|
|
ass_code.append(QStringLiteral("Spacing, Angle, "));
|
|
ass_code.append(QStringLiteral("BorderStyle, Outline, Shadow, "));
|
|
ass_code.append(QStringLiteral("Alignment, MarginL, MarginR, MarginV, "));
|
|
ass_code.append(QStringLiteral("Encoding\r\n"));
|
|
ass_code.append(QStringLiteral("Style: "));
|
|
|
|
// Name
|
|
ass_code.append(QStringLiteral("Default,"));
|
|
|
|
// Font{name,size}
|
|
ass_code.append(QStringLiteral("%1,%2,").arg(
|
|
k_ass_default_font, QString::number(k_ass_default_font_size)));
|
|
|
|
// {Primary,Secondary,Outline,Back}Colour
|
|
ass_code.append(QStringLiteral("&H%1,&H%2,&H%3,&H%4,")
|
|
.arg(QString::number(k_ass_default_primary_color, 16),
|
|
QString::number(k_ass_default_secondary_color, 16),
|
|
QString::number(k_ass_default_outline_color, 16),
|
|
QString::number(k_ass_default_back_color, 16)));
|
|
|
|
// Bold, Italic, Underline, StrikeOut
|
|
ass_code.append(
|
|
QStringLiteral("%1,%2,%3,%4,")
|
|
.arg(QString::number(k_ass_bold), QString::number(k_ass_italic),
|
|
QString::number(k_ass_underline), QString::number(k_ass_strike)));
|
|
|
|
// Scale{X,Y}
|
|
ass_code.append(QStringLiteral("100,100,"));
|
|
|
|
// Spacing, Angle
|
|
ass_code.append(QStringLiteral("0,0,"));
|
|
|
|
// BorderStyle, Outline, Shadow
|
|
ass_code.append(
|
|
QStringLiteral("%1,1,0,").arg(QString::number(k_ass_border_style)));
|
|
|
|
// Alignment, Margin[LRV]
|
|
ass_code.append(
|
|
QStringLiteral("%1,10,10,10,").arg(QString::number(k_ass_alignment)));
|
|
|
|
// Encoding
|
|
ass_code.append(QStringLiteral("0\r\n"));
|
|
ass_code.append(QStringLiteral("\r\n"));
|
|
ass_code.append(QStringLiteral("[Events]\r\n"));
|
|
ass_code.append(QStringLiteral(
|
|
"Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n"));
|
|
|
|
return ass_code;
|
|
}
|
|
|
|
void SubtitleParams::load(QXmlStreamReader *reader)
|
|
{
|
|
this->clear();
|
|
|
|
while (xml_read_next_start_element(reader)) {
|
|
if (reader->name() == QStringLiteral("streamindex")) {
|
|
set_stream_index(reader->readElementText().toInt());
|
|
} else if (reader->name() == QStringLiteral("enabled")) {
|
|
set_enabled(reader->readElementText().toInt());
|
|
} else if (reader->name() == QStringLiteral("subtitles")) {
|
|
while (xml_read_next_start_element(reader)) {
|
|
if (reader->name() == QStringLiteral("subtitle")) {
|
|
Rational in, out;
|
|
QString text;
|
|
|
|
XMLAttributeLoop(reader, attr)
|
|
{
|
|
if (attr.name() == QStringLiteral("in")) {
|
|
in = Rational::from_string(
|
|
attr.value().toString().toStdString());
|
|
} else if (attr.name() == QStringLiteral("out")) {
|
|
out = Rational::from_string(
|
|
attr.value().toString().toStdString());
|
|
}
|
|
}
|
|
|
|
text = reader->readElementText();
|
|
|
|
this->push_back(Subtitle(TimeRange(in, out), text));
|
|
} else {
|
|
reader->skipCurrentElement();
|
|
}
|
|
}
|
|
} else {
|
|
reader->skipCurrentElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SubtitleParams::save(QXmlStreamWriter *writer) const
|
|
{
|
|
writer->writeTextElement(QStringLiteral("streamindex"),
|
|
QString::number(stream_index_));
|
|
writer->writeTextElement(QStringLiteral("enabled"),
|
|
QString::number(enabled_));
|
|
|
|
writer->writeStartElement(QStringLiteral("subtitles"));
|
|
for (auto it = this->cbegin(); it != this->cend(); it++) {
|
|
writer->writeStartElement(QStringLiteral("subtitle"));
|
|
writer->writeAttribute(
|
|
QStringLiteral("in"),
|
|
QString::fromStdString(it->time().in().to_string()));
|
|
writer->writeAttribute(
|
|
QStringLiteral("out"),
|
|
QString::fromStdString(it->time().out().to_string()));
|
|
writer->writeCharacters(it->text());
|
|
writer->writeEndElement(); // subtitle
|
|
}
|
|
writer->writeEndElement(); // subtitles
|
|
}
|
|
|
|
}
|