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
+55 -87
View File
@@ -1,31 +1,39 @@
# SPDX-License-Identifier: GPL-2.0
#
# clang-format configuration file. Intended for clang-format >= 11.
#
# For more information, see:
#
# Documentation/dev-tools/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
@@ -37,43 +45,33 @@ BraceWrapping:
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: true
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
FixNamespaceComments: false
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 2
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
@@ -82,67 +80,37 @@ MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
# Taken from git's rules
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never
TabWidth: 4
UseTab: Always
...
+147
View File
@@ -0,0 +1,147 @@
# Generated from CLion Inspection settings
---
Checks: '-*,
bugprone-argument-comment,
bugprone-assert-side-effect,
bugprone-bad-signal-to-kill-thread,
bugprone-branch-clone,
bugprone-copy-constructor-init,
bugprone-dangling-handle,
bugprone-dynamic-static-initializers,
bugprone-fold-init-type,
bugprone-forward-declaration-namespace,
bugprone-forwarding-reference-overload,
bugprone-inaccurate-erase,
bugprone-incorrect-roundings,
bugprone-integer-division,
bugprone-lambda-function-name,
bugprone-macro-parentheses,
bugprone-macro-repeated-side-effects,
bugprone-misplaced-operator-in-strlen-in-alloc,
bugprone-misplaced-pointer-arithmetic-in-alloc,
bugprone-misplaced-widening-cast,
bugprone-move-forwarding-reference,
bugprone-multiple-statement-macro,
bugprone-no-escape,
bugprone-parent-virtual-call,
bugprone-posix-return,
bugprone-reserved-identifier,
bugprone-sizeof-container,
bugprone-sizeof-expression,
bugprone-spuriously-wake-up-functions,
bugprone-string-constructor,
bugprone-string-integer-assignment,
bugprone-string-literal-with-embedded-nul,
bugprone-suspicious-enum-usage,
bugprone-suspicious-include,
bugprone-suspicious-memset-usage,
bugprone-suspicious-missing-comma,
bugprone-suspicious-semicolon,
bugprone-suspicious-string-compare,
bugprone-suspicious-memory-comparison,
bugprone-suspicious-realloc-usage,
bugprone-swapped-arguments,
bugprone-terminating-continue,
bugprone-throw-keyword-missing,
bugprone-too-small-loop-variable,
bugprone-undefined-memory-manipulation,
bugprone-undelegated-constructor,
bugprone-unhandled-self-assignment,
bugprone-unused-raii,
bugprone-unused-return-value,
bugprone-use-after-move,
bugprone-virtual-near-miss,
cert-dcl21-cpp,
cert-dcl58-cpp,
cert-err34-c,
cert-err52-cpp,
cert-err60-cpp,
cert-flp30-c,
cert-msc50-cpp,
cert-msc51-cpp,
cert-str34-c,
cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-narrowing-conversions,
cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-slicing,
google-default-arguments,
google-explicit-constructor,
google-runtime-operator,
hicpp-exception-baseclass,
hicpp-multiway-paths-covered,
misc-misplaced-const,
misc-new-delete-overloads,
misc-no-recursion,
misc-non-copyable-objects,
misc-throw-by-value-catch-by-reference,
misc-unconventional-assign-operator,
misc-uniqueptr-reset-release,
modernize-avoid-bind,
modernize-concat-nested-namespaces,
modernize-deprecated-headers,
modernize-deprecated-ios-base-aliases,
modernize-loop-convert,
modernize-make-shared,
modernize-make-unique,
modernize-pass-by-value,
modernize-raw-string-literal,
modernize-redundant-void-arg,
modernize-replace-auto-ptr,
modernize-replace-disallow-copy-and-assign-macro,
modernize-replace-random-shuffle,
modernize-return-braced-init-list,
modernize-shrink-to-fit,
modernize-unary-static-assert,
modernize-use-auto,
modernize-use-bool-literals,
modernize-use-emplace,
modernize-use-equals-default,
modernize-use-equals-delete,
modernize-use-nodiscard,
modernize-use-noexcept,
modernize-use-nullptr,
modernize-use-override,
modernize-use-transparent-functors,
modernize-use-uncaught-exceptions,
mpi-buffer-deref,
mpi-type-mismatch,
openmp-use-default-none,
performance-faster-string-find,
performance-for-range-copy,
performance-implicit-conversion-in-loop,
performance-inefficient-algorithm,
performance-inefficient-string-concatenation,
performance-inefficient-vector-operation,
performance-move-const-arg,
performance-move-constructor-init,
performance-no-automatic-move,
performance-noexcept-move-constructor,
performance-trivially-destructible,
performance-type-promotion-in-math-fn,
performance-unnecessary-copy-initialization,
performance-unnecessary-value-param,
portability-simd-intrinsics,
readability-avoid-const-params-in-decls,
readability-const-return-type,
readability-container-size-empty,
readability-convert-member-functions-to-static,
readability-delete-null-pointer,
readability-deleted-default,
readability-inconsistent-declaration-parameter-name,
readability-make-member-function-const,
readability-misleading-indentation,
readability-misplaced-array-index,
readability-non-const-parameter,
readability-redundant-control-flow,
readability-redundant-declaration,
readability-redundant-function-ptr-dereference,
readability-redundant-smartptr-get,
readability-redundant-string-cstr,
readability-redundant-string-init,
readability-simplify-subscript-expr,
readability-static-accessed-through-instance,
readability-static-definition-in-anonymous-namespace,
readability-string-compare,
readability-uniqueptr-delete-release,
readability-use-anyofallof'
+57 -28
View File
@@ -28,7 +28,8 @@
#include "config/config.h"
namespace olive {
namespace olive
{
AudioManager *AudioManager::instance_ = nullptr;
@@ -55,35 +56,45 @@ void AudioManager::SetOutputNotifyInterval(int n)
output_buffer_->set_notify_interval(n);
}
int OutputCallback(const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
int OutputCallback(const void *input, void *output, unsigned long frameCount,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags, void *userData)
{
PreviewAudioDevice *device = static_cast<PreviewAudioDevice *>(userData);
qint64 max_read = frameCount * device->bytes_per_frame();
qint64 read_count = device->read(reinterpret_cast<char*>(output), max_read);
qint64 read_count =
device->read(reinterpret_cast<char *>(output), max_read);
if (read_count < max_read) {
memset(reinterpret_cast<uint8_t*>(output) + read_count, 0, max_read - read_count);
memset(reinterpret_cast<uint8_t *>(output) + read_count, 0,
max_read - read_count);
}
return paContinue;
}
int InputCallback(const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
int InputCallback(const void *input, void *output, unsigned long frameCount,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags, void *userData)
{
FFmpegEncoder *f = static_cast<FFmpegEncoder *>(userData);
AudioParams our_params = f->params().audio_params();
our_params.set_format(f->params().audio_params().format().to_packed_equivalent());
our_params.set_format(
f->params().audio_params().format().to_packed_equivalent());
f->WriteAudioData(our_params, reinterpret_cast<const uint8_t**>(&input), frameCount);
f->WriteAudioData(our_params, reinterpret_cast<const uint8_t **>(&input),
frameCount);
return paContinue;
}
bool AudioManager::PushToOutput(const AudioParams &params, const QByteArray &samples, QString *error)
bool AudioManager::PushToOutput(const AudioParams &params,
const QByteArray &samples, QString *error)
{
if (output_device_ == paNoDevice) {
if (error) *error = tr("No output device is set");
if (error)
*error = tr("No output device is set");
return false;
}
@@ -94,11 +105,15 @@ bool AudioManager::PushToOutput(const AudioParams &params, const QByteArray &sam
PaStreamParameters p = GetPortAudioParams(params, output_device_);
PaError r = Pa_OpenStream(&output_stream_, nullptr, &p, output_params_.sample_rate(), paFramesPerBufferUnspecified, paNoFlag, OutputCallback, output_buffer_);
PaError r = Pa_OpenStream(&output_stream_, nullptr, &p,
output_params_.sample_rate(),
paFramesPerBufferUnspecified, paNoFlag,
OutputCallback, output_buffer_);
if (r != paNoError) {
// Unhandled error
//qCritical() << "Failed to open output stream:" << Pa_GetErrorText(r);
if (error) *error = Pa_GetErrorText(r);
if (error)
*error = Pa_GetErrorText(r);
return false;
}
@@ -171,7 +186,8 @@ void AudioManager::SetOutputDevice(PaDeviceIndex device)
if (device == paNoDevice) {
qInfo() << "No output device found";
} else {
qInfo() << "Setting output audio device to" << Pa_GetDeviceInfo(device)->name;
qInfo() << "Setting output audio device to"
<< Pa_GetDeviceInfo(device)->name;
}
output_device_ = device;
@@ -184,7 +200,8 @@ void AudioManager::SetInputDevice(PaDeviceIndex device)
if (device == paNoDevice) {
qInfo() << "No input device found";
} else {
qInfo() << "Setting input audio device to" << Pa_GetDeviceInfo(device)->name;
qInfo() << "Setting input audio device to"
<< Pa_GetDeviceInfo(device)->name;
}
input_device_ = device;
@@ -197,7 +214,8 @@ void AudioManager::HardReset()
Pa_Initialize();
}
bool AudioManager::StartRecording(const EncodingParams &params, QString *error_str)
bool AudioManager::StartRecording(const EncodingParams &params,
QString *error_str)
{
if (input_device_ == paNoDevice) {
return false;
@@ -209,9 +227,13 @@ bool AudioManager::StartRecording(const EncodingParams &params, QString *error_s
return false;
}
PaStreamParameters p = GetPortAudioParams(params.audio_params(), input_device_);
PaStreamParameters p =
GetPortAudioParams(params.audio_params(), input_device_);
PaError r = Pa_OpenStream(&input_stream_, &p, nullptr, params.audio_params().sample_rate(), paFramesPerBufferUnspecified, paNoFlag, InputCallback, input_encoder_);
PaError r = Pa_OpenStream(&input_stream_, &p, nullptr,
params.audio_params().sample_rate(),
paFramesPerBufferUnspecified, paNoFlag,
InputCallback, input_encoder_);
if (r == paNoError) {
//const PaStreamInfo* info = Pa_GetStreamInfo(input_stream_);
r = Pa_StartStream(input_stream_);
@@ -248,28 +270,34 @@ void AudioManager::StopRecording()
PaDeviceIndex AudioManager::FindConfigDeviceByName(bool is_output_device)
{
QString entry = is_output_device ? QStringLiteral("AudioOutput") : QStringLiteral("AudioInput");
QString entry = is_output_device ? QStringLiteral("AudioOutput") :
QStringLiteral("AudioInput");
return FindDeviceByName(OLIVE_CONFIG_STR(entry).toString(), is_output_device);
return FindDeviceByName(OLIVE_CONFIG_STR(entry).toString(),
is_output_device);
}
PaDeviceIndex AudioManager::FindDeviceByName(const QString &s, bool is_output_device)
PaDeviceIndex AudioManager::FindDeviceByName(const QString &s,
bool is_output_device)
{
if (!s.isEmpty()) {
for (PaDeviceIndex i = 0, end = Pa_GetDeviceCount(); i < end; i++) {
const PaDeviceInfo *device = Pa_GetDeviceInfo(i);
if (((is_output_device && device->maxOutputChannels) || (!is_output_device && device->maxInputChannels))
&& !s.compare(device->name)) {
if (((is_output_device && device->maxOutputChannels) ||
(!is_output_device && device->maxInputChannels)) &&
!s.compare(device->name)) {
return i;
}
}
}
return is_output_device ? Pa_GetDefaultOutputDevice() : Pa_GetDefaultInputDevice();
return is_output_device ? Pa_GetDefaultOutputDevice() :
Pa_GetDefaultInputDevice();
}
PaStreamParameters AudioManager::GetPortAudioParams(const AudioParams &params, PaDeviceIndex device)
PaStreamParameters AudioManager::GetPortAudioParams(const AudioParams &params,
PaDeviceIndex device)
{
PaStreamParameters p;
@@ -282,10 +310,10 @@ PaStreamParameters AudioManager::GetPortAudioParams(const AudioParams &params, P
return p;
}
AudioManager::AudioManager() :
output_stream_(nullptr),
input_stream_(nullptr),
input_encoder_(nullptr)
AudioManager::AudioManager()
: output_stream_(nullptr)
, input_stream_(nullptr)
, input_encoder_(nullptr)
{
#ifdef PA_HAS_JACK
// PortAudio doesn't do a strcpy, so we need a const char that's readily accessible (i.e. not
@@ -304,7 +332,8 @@ AudioManager::AudioManager() :
output_buffer_ = new PreviewAudioDevice(this);
output_buffer_->open(PreviewAudioDevice::ReadWrite);
connect(output_buffer_, &PreviewAudioDevice::Notify, this, &AudioManager::OutputNotify);
connect(output_buffer_, &PreviewAudioDevice::Notify, this,
&AudioManager::OutputNotify);
}
AudioManager::~AudioManager()
+11 -8
View File
@@ -33,7 +33,8 @@
#include "render/audioplaybackcache.h"
#include "render/previewaudiodevice.h"
namespace olive {
namespace olive
{
/**
* @brief Audio input and output management class
@@ -41,8 +42,7 @@ namespace olive {
* Wraps around a QAudioOutput and AudioHybridDevice, connecting them together and exposing audio functionality to
* the rest of the system.
*/
class AudioManager : public QObject
{
class AudioManager : public QObject {
Q_OBJECT
public:
static void CreateInstance();
@@ -52,7 +52,8 @@ public:
void SetOutputNotifyInterval(int n);
bool PushToOutput(const AudioParams &params, const QByteArray& samples, QString *error = nullptr);
bool PushToOutput(const AudioParams &params, const QByteArray &samples,
QString *error = nullptr);
void ClearBufferedOutput();
@@ -74,14 +75,17 @@ public:
void HardReset();
bool StartRecording(const EncodingParams &params, QString *error_str = nullptr);
bool StartRecording(const EncodingParams &params,
QString *error_str = nullptr);
void StopRecording();
static PaDeviceIndex FindConfigDeviceByName(bool is_output_device);
static PaDeviceIndex FindDeviceByName(const QString &s, bool is_output_device);
static PaDeviceIndex FindDeviceByName(const QString &s,
bool is_output_device);
static PaStreamParameters GetPortAudioParams(const AudioParams &p, PaDeviceIndex device);
static PaStreamParameters GetPortAudioParams(const AudioParams &p,
PaDeviceIndex device);
signals:
void OutputNotify();
@@ -108,7 +112,6 @@ private:
PaStream *input_stream_;
FFmpegEncoder *input_encoder_;
};
}
+47 -28
View File
@@ -29,7 +29,8 @@ extern "C" {
#include "common/ffmpegutils.h"
namespace olive {
namespace olive
{
AudioProcessor::AudioProcessor()
{
@@ -43,7 +44,8 @@ AudioProcessor::~AudioProcessor()
Close();
}
bool AudioProcessor::Open(const AudioParams &from, const AudioParams &to, double tempo)
bool AudioProcessor::Open(const AudioParams &from, const AudioParams &to,
double tempo)
{
if (filter_graph_) {
qWarning() << "Tried to open a processor that was already open";
@@ -61,17 +63,18 @@ bool AudioProcessor::Open(const AudioParams &from, const AudioParams &to, double
// Set up audio buffer args
char filter_args[200];
snprintf(filter_args, 200, "time_base=%d/%d:sample_rate=%d:sample_fmt=%d:channel_layout=0x%" PRIx64,
1,
from.sample_rate(),
from.sample_rate(),
from_fmt_,
snprintf(
filter_args, 200,
"time_base=%d/%d:sample_rate=%d:sample_fmt=%d:channel_layout=0x%" PRIx64,
1, from.sample_rate(), from.sample_rate(), from_fmt_,
from.channel_layout().u.mask);
int r;
// Create buffersrc (input)
r = avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("abuffer"), "in", filter_args, nullptr, filter_graph_);
r = avfilter_graph_create_filter(&buffersrc_ctx_,
avfilter_get_by_name("abuffer"), "in",
filter_args, nullptr, filter_graph_);
if (r < 0) {
qCritical() << "Failed to create buffersrc:" << r;
Close();
@@ -96,16 +99,16 @@ bool AudioProcessor::Open(const AudioParams &from, const AudioParams &to, double
speed_log -= whole;
for (int i = 0; i <= whole; i++) {
double filter_tempo = (i == whole) ? std::pow(base, speed_log) : base;
double filter_tempo = (i == whole) ? std::pow(base, speed_log) :
base;
/*
if (qFuzzyCompare(filter_tempo, 1.0)) {
// This filter would do nothing
continue;
}*/
previous_filter = CreateTempoFilter(filter_graph_,
previous_filter,
filter_tempo);
previous_filter =
CreateTempoFilter(filter_graph_, previous_filter, filter_tempo);
if (!previous_filter) {
qCritical() << "Failed to create audio tempo filter";
@@ -118,19 +121,24 @@ bool AudioProcessor::Open(const AudioParams &from, const AudioParams &to, double
// Create conversion filter
auto ch1 = from.channel_layout();
auto ch2 = to.channel_layout();
if (from.sample_rate() != to.sample_rate() || av_channel_layout_compare(&ch1, &ch2) || from.format() != to.format()
|| (to.format().is_planar() && create_tempo)) { // Tempo processor automatically converts to packed,
if (from.sample_rate() != to.sample_rate() ||
av_channel_layout_compare(&ch1, &ch2) || from.format() != to.format() ||
(to.format().is_planar() &&
create_tempo)) { // Tempo processor automatically converts to packed,
// so if the desired output is planar, it'll need
// to be converted
snprintf(filter_args, 200, "sample_fmts=%s:sample_rates=%d:channel_layouts=0x%" PRIx64,
av_get_sample_fmt_name(to_fmt_),
to.sample_rate(),
snprintf(filter_args, 200,
"sample_fmts=%s:sample_rates=%d:channel_layouts=0x%" PRIx64,
av_get_sample_fmt_name(to_fmt_), to.sample_rate(),
to.channel_layout().u.mask);
AVFilterContext *c;
r = avfilter_graph_create_filter(&c, avfilter_get_by_name("aformat"), "fmt", filter_args, nullptr, filter_graph_);
r = avfilter_graph_create_filter(&c, avfilter_get_by_name("aformat"),
"fmt", filter_args, nullptr,
filter_graph_);
if (r < 0) {
qCritical() << "Failed to create format conversion filter:" << r << filter_args;
qCritical() << "Failed to create format conversion filter:" << r
<< filter_args;
Close();
return false;
}
@@ -146,7 +154,9 @@ bool AudioProcessor::Open(const AudioParams &from, const AudioParams &to, double
}
// Create buffersink (output)
r = avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("abuffersink"), "out", nullptr, nullptr, filter_graph_);
r = avfilter_graph_create_filter(&buffersink_ctx_,
avfilter_get_by_name("abuffersink"), "out",
nullptr, nullptr, filter_graph_);
if (r < 0) {
qCritical() << "Failed to create buffersink:" << r;
Close();
@@ -214,7 +224,8 @@ void AudioProcessor::Close()
}
}
int AudioProcessor::Convert(float **in, int nb_in_samples, AudioProcessor::Buffer *output)
int AudioProcessor::Convert(float **in, int nb_in_samples,
AudioProcessor::Buffer *output)
{
if (!IsOpen()) {
qCritical() << "Tried to convert on closed processor";
@@ -231,7 +242,8 @@ int AudioProcessor::Convert(float **in, int nb_in_samples, AudioProcessor::Buffe
in_frame_->linesize[i] = from_.samples_to_bytes(nb_in_samples);
}
r = av_buffersrc_add_frame_flags(buffersrc_ctx_, in_frame_, AV_BUFFERSRC_FLAG_KEEP_REF);
r = av_buffersrc_add_frame_flags(buffersrc_ctx_, in_frame_,
AV_BUFFERSRC_FLAG_KEEP_REF);
if (r < 0) {
qCritical() << "Failed to add frame to buffersrc:" << r;
return r;
@@ -263,14 +275,16 @@ int AudioProcessor::Convert(float **in, int nb_in_samples, AudioProcessor::Buffe
break;
}
int nb_bytes = out_frame_->nb_samples * to_.bytes_per_sample_per_channel();
int nb_bytes =
out_frame_->nb_samples * to_.bytes_per_sample_per_channel();
if (to_.format().is_packed()) {
nb_bytes *= to_.channel_count();
}
for (int i = 0; i < nb_channels; i++) {
result[i].resize(byte_offset + nb_bytes);
memcpy(result[i].data() + byte_offset, out_frame_->data[i], nb_bytes);
memcpy(result[i].data() + byte_offset, out_frame_->data[i],
nb_bytes);
}
byte_offset += nb_bytes;
}
@@ -282,13 +296,16 @@ int AudioProcessor::Convert(float **in, int nb_in_samples, AudioProcessor::Buffe
void AudioProcessor::Flush()
{
int r = av_buffersrc_add_frame_flags(buffersrc_ctx_, nullptr, AV_BUFFERSRC_FLAG_KEEP_REF);
int r = av_buffersrc_add_frame_flags(buffersrc_ctx_, nullptr,
AV_BUFFERSRC_FLAG_KEEP_REF);
if (r < 0) {
qCritical() << "Failed to flush:" << r;
}
}
AVFilterContext *AudioProcessor::CreateTempoFilter(AVFilterGraph* graph, AVFilterContext* link, const double &tempo)
AVFilterContext *AudioProcessor::CreateTempoFilter(AVFilterGraph *graph,
AVFilterContext *link,
const double &tempo)
{
// Set up tempo param, which is taken as a C string
char speed_param[20];
@@ -296,8 +313,10 @@ AVFilterContext *AudioProcessor::CreateTempoFilter(AVFilterGraph* graph, AVFilte
AVFilterContext *tempo_ctx = nullptr;
if (avfilter_graph_create_filter(&tempo_ctx, avfilter_get_by_name("atempo"), "atempo", speed_param, nullptr, graph) >= 0
&& avfilter_link(link, 0, tempo_ctx, 0) == 0) {
if (avfilter_graph_create_filter(&tempo_ctx, avfilter_get_by_name("atempo"),
"atempo", speed_param, nullptr,
graph) >= 0 &&
avfilter_link(link, 0, tempo_ctx, 0) == 0) {
return tempo_ctx;
}
+20 -9
View File
@@ -31,12 +31,12 @@ extern "C" {
#include "common/define.h"
namespace olive {
namespace olive
{
using namespace core;
class AudioProcessor
{
class AudioProcessor {
public:
AudioProcessor();
@@ -44,22 +44,34 @@ public:
DISABLE_COPY_MOVE(AudioProcessor)
bool Open(const AudioParams &from, const AudioParams &to, double tempo = 1.0);
bool Open(const AudioParams &from, const AudioParams &to,
double tempo = 1.0);
void Close();
bool IsOpen() const { return filter_graph_; }
bool IsOpen() const
{
return filter_graph_;
}
using Buffer = QVector<QByteArray>;
int Convert(float **in, int nb_in_samples, AudioProcessor::Buffer *output);
void Flush();
const AudioParams &from() const { return from_; }
const AudioParams &to() const { return to_; }
const AudioParams &from() const
{
return from_;
}
const AudioParams &to() const
{
return to_;
}
private:
static AVFilterContext* CreateTempoFilter(AVFilterGraph *graph, AVFilterContext *link, const double& tempo);
static AVFilterContext *CreateTempoFilter(AVFilterGraph *graph,
AVFilterContext *link,
const double &tempo);
AVFilterGraph *filter_graph_;
@@ -76,7 +88,6 @@ private:
AVFrame *in_frame_;
AVFrame *out_frame_;
};
}
+116 -60
View File
@@ -25,23 +25,30 @@
#include "config/config.h"
namespace olive {
namespace olive
{
const rational AudioVisualWaveform::kMinimumSampleRate = rational(1, 8);
const rational AudioVisualWaveform::kMaximumSampleRate = 1024;
AudioVisualWaveform::AudioVisualWaveform() :
channels_(0)
AudioVisualWaveform::AudioVisualWaveform()
: channels_(0)
{
for (rational i = kMinimumSampleRate; i <= kMaximumSampleRate; i *= 2) {
mipmapped_data_.insert({ i, Sample() });
}
}
void AudioVisualWaveform::OverwriteSamplesFromBuffer(const SampleBuffer &samples, int sample_rate, const rational &start, double target_rate, Sample& data, size_t &start_index, size_t &samples_length)
void AudioVisualWaveform::OverwriteSamplesFromBuffer(
const SampleBuffer &samples, int sample_rate, const rational &start,
double target_rate, Sample &data, size_t &start_index,
size_t &samples_length)
{
start_index = time_to_samples(start, target_rate);
samples_length = time_to_samples(static_cast<double>(samples.sample_count()) / static_cast<double>(sample_rate), target_rate);
samples_length =
time_to_samples(static_cast<double>(samples.sample_count()) /
static_cast<double>(sample_rate),
target_rate);
size_t end_index = start_index + samples_length;
if (data.size() < end_index) {
@@ -52,22 +59,26 @@ void AudioVisualWaveform::OverwriteSamplesFromBuffer(const SampleBuffer &samples
for (size_t i = 0; i < samples_length; i += channels_) {
size_t src_start = qRound((double(i) * chunk_size)) / channels_;
size_t src_end = qMin(size_t(qRound64((double(i + channels_) * chunk_size))) / channels_, samples.sample_count());
size_t src_end = qMin(
size_t(qRound64((double(i + channels_) * chunk_size))) / channels_,
samples.sample_count());
Sample summary = SumSamples(samples,
src_start,
src_end - src_start);
Sample summary = SumSamples(samples, src_start, src_end - src_start);
memcpy(&data.data()[i + start_index],
summary.data(),
memcpy(&data.data()[i + start_index], summary.data(),
summary.size() * sizeof(SamplePerChannel));
}
}
void AudioVisualWaveform::OverwriteSamplesFromMipmap(const AudioVisualWaveform::Sample &input, double input_sample_rate, size_t &input_start, size_t &input_length, const rational &start, double output_rate, AudioVisualWaveform::Sample &output_data)
void AudioVisualWaveform::OverwriteSamplesFromMipmap(
const AudioVisualWaveform::Sample &input, double input_sample_rate,
size_t &input_start, size_t &input_length, const rational &start,
double output_rate, AudioVisualWaveform::Sample &output_data)
{
size_t start_index = time_to_samples(start, output_rate);
size_t samples_length = time_to_samples(static_cast<double>(input_length / channels_) / input_sample_rate, output_rate);
size_t samples_length = time_to_samples(
static_cast<double>(input_length / channels_) / input_sample_rate,
output_rate);
size_t end_index = start_index + samples_length;
if (output_data.size() < end_index) {
@@ -78,10 +89,11 @@ void AudioVisualWaveform::OverwriteSamplesFromMipmap(const AudioVisualWaveform::
size_t chunk_size = input_sample_rate / output_rate;
for (size_t i = 0; i < samples_length; i += channels_) {
Sample summary = ReSumSamples(&input.data()[input_start + (i*chunk_size)], chunk_size * channels_, channels_);
Sample summary =
ReSumSamples(&input.data()[input_start + (i * chunk_size)],
chunk_size * channels_, channels_);
memcpy(&output_data.data()[i + start_index],
summary.data(),
memcpy(&output_data.data()[i + start_index], summary.data(),
summary.size() * sizeof(SamplePerChannel));
}
@@ -98,7 +110,9 @@ void AudioVisualWaveform::ValidateVirtualStart(const rational &new_start)
}
}
void AudioVisualWaveform::OverwriteSamples(const SampleBuffer &samples, int sample_rate, const rational &start)
void AudioVisualWaveform::OverwriteSamples(const SampleBuffer &samples,
int sample_rate,
const rational &start)
{
if (!channels_) {
qWarning() << "Failed to write samples - channel count is zero";
@@ -110,7 +124,10 @@ void AudioVisualWaveform::OverwriteSamples(const SampleBuffer &samples, int samp
// Process the largest mipmap directly for the samples
auto current_mipmap = mipmapped_data_.rbegin();
size_t input_start, input_length;
OverwriteSamplesFromBuffer(samples, sample_rate, start - virtual_start_, current_mipmap->first.toDouble(), current_mipmap->second, input_start, input_length);
OverwriteSamplesFromBuffer(samples, sample_rate, start - virtual_start_,
current_mipmap->first.toDouble(),
current_mipmap->second, input_start,
input_length);
while (true) {
// For each smaller mipmap, we just process from the mipmap before it, making each one
@@ -121,16 +138,20 @@ void AudioVisualWaveform::OverwriteSamples(const SampleBuffer &samples, int samp
break;
}
OverwriteSamplesFromMipmap(previous_mipmap->second, previous_mipmap->first.toDouble(),
input_start, input_length, start - virtual_start_, current_mipmap->first.toDouble(),
current_mipmap->second);
OverwriteSamplesFromMipmap(
previous_mipmap->second, previous_mipmap->first.toDouble(),
input_start, input_length, start - virtual_start_,
current_mipmap->first.toDouble(), current_mipmap->second);
}
rational sample_length(samples.sample_count(), sample_rate);
length_ = qMax(length_, start + sample_length);
}
void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const rational &dest, const rational& offset, const rational& length)
void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums,
const rational &dest,
const rational &offset,
const rational &length)
{
ValidateVirtualStart(dest);
@@ -143,7 +164,8 @@ void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const r
double rate_dbl = rate.toDouble();
// Get our destination sample
size_t our_start_index = time_to_samples(dest - virtual_start_, rate_dbl);
size_t our_start_index =
time_to_samples(dest - virtual_start_, rate_dbl);
// Get our source sample
size_t their_start_index = time_to_samples(offset, rate_dbl);
@@ -166,15 +188,19 @@ void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const r
our_arr.resize(end_index);
}
memcpy(reinterpret_cast<char*>(our_arr.data()) + our_start_index * sizeof(SamplePerChannel),
reinterpret_cast<const char*>(their_arr.data()) + their_start_index * sizeof(SamplePerChannel),
memcpy(reinterpret_cast<char *>(our_arr.data()) +
our_start_index * sizeof(SamplePerChannel),
reinterpret_cast<const char *>(their_arr.data()) +
their_start_index * sizeof(SamplePerChannel),
copy_len * sizeof(SamplePerChannel));
}
length_ = qMax(length_, dest + ((length.isNull()) ? sums.length() - offset : length));
length_ = qMax(length_, dest + ((length.isNull()) ? sums.length() - offset :
length));
}
void AudioVisualWaveform::OverwriteSilence(const rational &start, const rational &length)
void AudioVisualWaveform::OverwriteSilence(const rational &start,
const rational &length)
{
ValidateVirtualStart(start);
@@ -186,7 +212,8 @@ void AudioVisualWaveform::OverwriteSilence(const rational &start, const rational
double rate_dbl = rate.toDouble();
// Get our destination sample
size_t our_start_index = time_to_samples(start - virtual_start_, rate_dbl);
size_t our_start_index =
time_to_samples(start - virtual_start_, rate_dbl);
size_t our_length_index = time_to_samples(length, rate_dbl);
size_t our_end_index = our_start_index + our_length_index;
@@ -194,7 +221,9 @@ void AudioVisualWaveform::OverwriteSilence(const rational &start, const rational
our_arr.resize(our_end_index);
}
memset(reinterpret_cast<char*>(our_arr.data()) + our_start_index * sizeof(SamplePerChannel), 0, our_length_index * sizeof(SamplePerChannel));
memset(reinterpret_cast<char *>(our_arr.data()) +
our_start_index * sizeof(SamplePerChannel),
0, our_length_index * sizeof(SamplePerChannel));
}
length_ = qMax(length_, start + length);
@@ -242,7 +271,8 @@ AudioVisualWaveform AudioVisualWaveform::Mid(const rational &offset) const
return mid;
}
AudioVisualWaveform AudioVisualWaveform::Mid(const rational &offset, const rational &length) const
AudioVisualWaveform AudioVisualWaveform::Mid(const rational &offset,
const rational &length) const
{
AudioVisualWaveform mid = *this;
@@ -276,7 +306,9 @@ void AudioVisualWaveform::TrimRange(const rational &in, const rational &length)
Resize(length);
}
AudioVisualWaveform::Sample AudioVisualWaveform::GetSummaryFromTime(const rational &start, const rational &length) const
AudioVisualWaveform::Sample
AudioVisualWaveform::GetSummaryFromTime(const rational &start,
const rational &length) const
{
// Find mipmap that requires
auto using_mipmap = GetMipmapForScale(length.flipped().toDouble());
@@ -294,14 +326,16 @@ AudioVisualWaveform::Sample AudioVisualWaveform::GetSummaryFromTime(const ration
// Based on the above `min`, if sample length <= 0, that means start_sample >= the size of the
// array and nothing can be returned.
if (sample_length > 0) {
return ReSumSamples(&mipmap_data.data()[start_sample], sample_length, channels_);
return ReSumSamples(&mipmap_data.data()[start_sample], sample_length,
channels_);
}
// Return null samples
return AudioVisualWaveform::Sample(channel_count(), { 0, 0 });
}
void ExpandMinMaxChannel(const float *a, size_t length, float &min_val, float &max_val)
void ExpandMinMaxChannel(const float *a, size_t length, float &min_val,
float &max_val)
{
#if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM)
// SSE optimized
@@ -344,13 +378,18 @@ void ExpandMinMaxChannel(const float *a, size_t length, float &min_val, float &m
#endif
}
AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(const SampleBuffer &samples, size_t start_index, size_t length)
AudioVisualWaveform::Sample
AudioVisualWaveform::SumSamples(const SampleBuffer &samples, size_t start_index,
size_t length)
{
int channels = samples.audio_params().channel_count();
AudioVisualWaveform::Sample summed_samples(channels);
for (int channel=0; channel<samples.audio_params().channel_count(); channel++) {
ExpandMinMaxChannel(samples.data(channel) + start_index, length, summed_samples[channel].min, summed_samples[channel].max);
for (int channel = 0; channel < samples.audio_params().channel_count();
channel++) {
ExpandMinMaxChannel(samples.data(channel) + start_index, length,
summed_samples[channel].min,
summed_samples[channel].max);
}
// for reference: this approximation is n x faster (and less accurate) for a n-tracks clip
@@ -361,15 +400,16 @@ AudioVisualWaveform::Sample AudioVisualWaveform::SumSamples(const SampleBuffer &
return summed_samples;
}
AudioVisualWaveform::Sample AudioVisualWaveform::ReSumSamples(const SamplePerChannel* samples,
size_t nb_samples,
int nb_channels)
AudioVisualWaveform::Sample
AudioVisualWaveform::ReSumSamples(const SamplePerChannel *samples,
size_t nb_samples, int nb_channels)
{
AudioVisualWaveform::Sample summed_samples(nb_channels);
for (size_t i = 0; i < nb_samples; i += nb_channels) {
for (int j = 0; j < nb_channels; j++) {
const AudioVisualWaveform::SamplePerChannel& sample = samples[i + j];
const AudioVisualWaveform::SamplePerChannel &sample =
samples[i + j];
if (sample.min < summed_samples[j].min) {
summed_samples[j].min = sample.min;
@@ -384,13 +424,13 @@ AudioVisualWaveform::Sample AudioVisualWaveform::ReSumSamples(const SamplePerCha
return summed_samples;
}
template <typename T>
inline int round_away_from_zero(T t)
template <typename T> inline int round_away_from_zero(T t)
{
return (t < 0) ? std::floor(t) : std::ceil(t);
}
void AudioVisualWaveform::DrawSample(QPainter *painter, const Sample& sample, int x, int y, int height, bool rectified)
void AudioVisualWaveform::DrawSample(QPainter *painter, const Sample &sample,
int x, int y, int height, bool rectified)
{
if (sample.empty()) {
return;
@@ -408,24 +448,29 @@ void AudioVisualWaveform::DrawSample(QPainter *painter, const Sample& sample, in
int diff = round_away_from_zero((max - min) * channel_half_height);
painter->drawLine(x,
channel_bottom - diff,
x,
channel_bottom);
painter->drawLine(x, channel_bottom - diff, x, channel_bottom);
} else {
int channel_mid = y + channel_height * i + channel_half_height;
// We subtract the sample so that positive Y values go up on the screen rather than down,
// which is how waveforms are usually rendered
painter->drawLine(x,
channel_mid - round_away_from_zero(min * static_cast<float>(channel_half_height)),
painter->drawLine(
x,
channel_mid - round_away_from_zero(max * static_cast<float>(channel_half_height)));
channel_mid -
round_away_from_zero(
min * static_cast<float>(channel_half_height)),
x,
channel_mid -
round_away_from_zero(
max * static_cast<float>(channel_half_height)));
}
}
}
void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, const double& scale, const AudioVisualWaveform &samples, const rational& start_time)
void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect &rect,
const double &scale,
const AudioVisualWaveform &samples,
const rational &start_time)
{
if (samples.mipmapped_data_.empty()) {
return;
@@ -437,7 +482,8 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
double rate_dbl = rate.toDouble();
const Sample &arr = using_mipmap->second;
size_t start_sample_index = samples.time_to_samples(start_time - samples.virtual_start_, rate_dbl);
size_t start_sample_index =
samples.time_to_samples(start_time - samples.virtual_start_, rate_dbl);
if (start_sample_index >= arr.size()) {
return;
@@ -464,12 +510,18 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
break;
}
next_sample_index = std::min(arr.size(),
size_t(start_sample_index + std::floor(rate_dbl * static_cast<double>(i - rect.x() + 1) / scale) * samples.channel_count()));
next_sample_index = std::min(
arr.size(),
size_t(start_sample_index +
std::floor(rate_dbl * static_cast<double>(i - rect.x() + 1) /
scale) *
samples.channel_count()));
if (summary_index != sample_index) {
summary = AudioVisualWaveform::ReSumSamples(&arr.at(sample_index),
qMax(size_t(samples.channel_count()), next_sample_index - sample_index),
summary = AudioVisualWaveform::ReSumSamples(
&arr.at(sample_index),
qMax(size_t(samples.channel_count()),
next_sample_index - sample_index),
samples.channel_count());
summary_index = sample_index;
}
@@ -478,20 +530,24 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
}
}
size_t AudioVisualWaveform::time_to_samples(const rational &time, double sample_rate) const
size_t AudioVisualWaveform::time_to_samples(const rational &time,
double sample_rate) const
{
return time_to_samples(time.toDouble(), sample_rate);
}
size_t AudioVisualWaveform::time_to_samples(const double &time, double sample_rate) const
size_t AudioVisualWaveform::time_to_samples(const double &time,
double sample_rate) const
{
return std::floor(time * sample_rate) * channels_;
}
std::map<rational, AudioVisualWaveform::Sample>::const_iterator AudioVisualWaveform::GetMipmapForScale(double scale) const
std::map<rational, AudioVisualWaveform::Sample>::const_iterator
AudioVisualWaveform::GetMipmapForScale(double scale) const
{
// Find largest mipmap for this scale (or the largest if we don't find one sufficient)
for (auto it=mipmapped_data_.cbegin(); it!=mipmapped_data_.cend(); it++) {
for (auto it = mipmapped_data_.cbegin(); it != mipmapped_data_.cend();
it++) {
if (it->first.toDouble() >= scale) {
return it;
}
+32 -13
View File
@@ -25,7 +25,8 @@
#include <QPainter>
#include <QVector>
namespace olive {
namespace olive
{
using namespace core;
@@ -66,7 +67,8 @@ public:
*
* Starting at `start`, writes samples over anything in the buffer, expanding it if necessary.
*/
void OverwriteSamples(const SampleBuffer &samples, int sample_rate, const rational& start = 0);
void OverwriteSamples(const SampleBuffer &samples, int sample_rate,
const rational &start = 0);
/**
* @brief Replaces sums at a certain range in this visual waveform
@@ -87,42 +89,60 @@ public:
*
* Maximum length of `sums` to overwrite with.
*/
void OverwriteSums(const AudioVisualWaveform& sums, const rational& dest, const rational& offset = 0, const rational &length = 0);
void OverwriteSums(const AudioVisualWaveform &sums, const rational &dest,
const rational &offset = 0, const rational &length = 0);
void OverwriteSilence(const rational &start, const rational &length);
void TrimIn(rational length);
AudioVisualWaveform Mid(const rational &offset) const;
AudioVisualWaveform Mid(const rational &offset, const rational &length) const;
AudioVisualWaveform Mid(const rational &offset,
const rational &length) const;
void Resize(const rational &length);
void TrimRange(const rational &in, const rational &length);
Sample GetSummaryFromTime(const rational& start, const rational& length) const;
Sample GetSummaryFromTime(const rational &start,
const rational &length) const;
static Sample SumSamples(const SampleBuffer &samples, size_t start_index, size_t length);
static Sample SumSamples(const SampleBuffer &samples, size_t start_index,
size_t length);
static Sample ReSumSamples(const SamplePerChannel *samples, size_t nb_samples, int nb_channels);
static Sample ReSumSamples(const SamplePerChannel *samples,
size_t nb_samples, int nb_channels);
static void DrawSample(QPainter* painter, const Sample &sample, int x, int y, int height, bool rectified);
static void DrawSample(QPainter *painter, const Sample &sample, int x,
int y, int height, bool rectified);
static void DrawWaveform(QPainter* painter, const QRect &rect, const double &scale, const AudioVisualWaveform& samples, const rational &start_time);
static void DrawWaveform(QPainter *painter, const QRect &rect,
const double &scale,
const AudioVisualWaveform &samples,
const rational &start_time);
// Must be a power of 2
static const rational kMinimumSampleRate;
static const rational kMaximumSampleRate;
private:
void OverwriteSamplesFromBuffer(const SampleBuffer &samples, int sample_rate, const rational& start, double target_rate, Sample &data, size_t &start_index, size_t &samples_length);
void OverwriteSamplesFromBuffer(const SampleBuffer &samples,
int sample_rate, const rational &start,
double target_rate, Sample &data,
size_t &start_index,
size_t &samples_length);
void OverwriteSamplesFromMipmap(const Sample& input, double input_sample_rate, size_t &input_start, size_t &input_length, const rational& start, double output_rate, Sample &output_data);
void OverwriteSamplesFromMipmap(const Sample &input,
double input_sample_rate,
size_t &input_start, size_t &input_length,
const rational &start, double output_rate,
Sample &output_data);
size_t time_to_samples(const rational &time, double sample_rate) const;
size_t time_to_samples(const double &time, double sample_rate) const;
std::map<rational, Sample>::const_iterator GetMipmapForScale(double scale) const;
std::map<rational, Sample>::const_iterator
GetMipmapForScale(double scale) const;
void ValidateVirtualStart(const rational &new_start);
@@ -133,7 +153,6 @@ private:
std::map<rational, Sample> mipmapped_data_;
rational length_;
};
}
+2 -2
View File
@@ -20,11 +20,11 @@
#include "cliexportmanager.h"
namespace olive {
namespace olive
{
CLIExportManager::CLIExportManager()
{
}
}
+3 -3
View File
@@ -23,10 +23,10 @@
#include "task/export/export.h"
namespace olive {
class CLIExportManager : public QObject
namespace olive
{
class CLIExportManager : public QObject {
public:
CLIExportManager();
};
+9 -7
View File
@@ -22,13 +22,14 @@
#include <iostream>
namespace olive {
namespace olive
{
CLIProgressDialog::CLIProgressDialog(const QString& title, QObject *parent) :
QObject(parent),
title_(title),
progress_(-1),
drawn_(false)
CLIProgressDialog::CLIProgressDialog(const QString &title, QObject *parent)
: QObject(parent)
, title_(title)
, progress_(-1)
, drawn_(false)
{
SetProgress(0);
}
@@ -51,7 +52,8 @@ void CLIProgressDialog::Update()
QString sized_title = title_;
if (title_.size() > title_columns) {
sized_title = title_.left(title_columns - 3).append(QStringLiteral("..."));
sized_title =
title_.left(title_columns - 3).append(QStringLiteral("..."));
} else {
sized_title = title_;
}
+3 -4
View File
@@ -26,10 +26,10 @@
#include "common/define.h"
namespace olive {
class CLIProgressDialog : public QObject
namespace olive
{
class CLIProgressDialog : public QObject {
public:
CLIProgressDialog(const QString &title, QObject *parent = nullptr);
@@ -44,7 +44,6 @@ private:
double progress_;
bool drawn_;
};
}
+5 -4
View File
@@ -20,11 +20,12 @@
#include "clitaskdialog.h"
namespace olive {
namespace olive
{
CLITaskDialog::CLITaskDialog(Task *task, QObject* parent) :
CLIProgressDialog(task->GetTitle(), parent),
task_(task)
CLITaskDialog::CLITaskDialog(Task *task, QObject *parent)
: CLIProgressDialog(task->GetTitle(), parent)
, task_(task)
{
connect(task_, &Task::ProgressChanged, this, &CLITaskDialog::SetProgress);
}
+3 -4
View File
@@ -24,10 +24,10 @@
#include "cli/cliprogress/cliprogressdialog.h"
#include "task/task.h"
namespace olive {
class CLITaskDialog : public CLIProgressDialog
namespace olive
{
class CLITaskDialog : public CLIProgressDialog {
Q_OBJECT
public:
CLITaskDialog(Task *task, QObject *parent = nullptr);
@@ -36,7 +36,6 @@ public:
private:
Task *task_;
};
}
+23 -9
View File
@@ -4,17 +4,21 @@
#include "task/taskmanager.h"
namespace olive {
namespace olive
{
ConformManager *ConformManager::instance_ = nullptr;
ConformManager::Conform ConformManager::GetConformState(const QString &decoder_id, const QString &cache_path, const Decoder::CodecStream &stream, const AudioParams &params, bool wait)
ConformManager::Conform ConformManager::GetConformState(
const QString &decoder_id, const QString &cache_path,
const Decoder::CodecStream &stream, const AudioParams &params, bool wait)
{
// Mutex because we'll need to check the status of a conform task
QMutexLocker locker(&mutex_);
// Return existing conform if exists
QVector<QString> filenames = GetConformedFilename(cache_path, stream, params);
QVector<QString> filenames =
GetConformedFilename(cache_path, stream, params);
if (AllConformsExist(filenames)) {
return { kConformExists, filenames, nullptr };
}
@@ -39,12 +43,17 @@ ConformManager::Conform ConformManager::GetConformState(const QString &decoder_i
working_filenames[i].append(QStringLiteral(".working"));
}
conforming_task = new ConformTask(decoder_id, stream, params, working_filenames);
connect(conforming_task, &ConformTask::Finished, this, &ConformManager::ConformTaskFinished);
conforming_task =
new ConformTask(decoder_id, stream, params, working_filenames);
connect(conforming_task, &ConformTask::Finished, this,
&ConformManager::ConformTaskFinished);
conforming_task->moveToThread(TaskManager::instance()->thread());
QMetaObject::invokeMethod(TaskManager::instance(), "AddTask", Qt::QueuedConnection, Q_ARG(Task *, conforming_task));
QMetaObject::invokeMethod(TaskManager::instance(), "AddTask",
Qt::QueuedConnection,
Q_ARG(Task *, conforming_task));
conforming_.append({stream, params, conforming_task, working_filenames, filenames});
conforming_.append(
{ stream, params, conforming_task, working_filenames, filenames });
}
if (wait) {
@@ -57,12 +66,17 @@ ConformManager::Conform ConformManager::GetConformState(const QString &decoder_i
return { kConformGenerating, QVector<QString>(), conforming_task };
}
QVector<QString> ConformManager::GetConformedFilename(const QString &cache_path, const Decoder::CodecStream &stream, const AudioParams &params)
QVector<QString>
ConformManager::GetConformedFilename(const QString &cache_path,
const Decoder::CodecStream &stream,
const AudioParams &params)
{
QVector<QString> filenames(params.channel_count());
for (int i = 0; i < filenames.size(); i++) {
QString index_fn = QStringLiteral("%1-%2.%3.%4.%5.%6.pcm").arg(FileFunctions::GetUniqueFileIdentifier(stream.filename()),
QString index_fn =
QStringLiteral("%1-%2.%3.%4.%5.%6.pcm")
.arg(FileFunctions::GetUniqueFileIdentifier(stream.filename()),
QString::number(stream.stream()),
QString::number(params.sample_rate()),
QString::number(params.format()),
+13 -11
View File
@@ -7,10 +7,10 @@
#include "decoder.h"
#include "task/conform/conform.h"
namespace olive {
class ConformManager : public QObject
namespace olive
{
class ConformManager : public QObject {
Q_OBJECT
public:
static void CreateInstance()
@@ -31,10 +31,7 @@ public:
return instance_;
}
enum ConformState {
kConformExists,
kConformGenerating
};
enum ConformState { kConformExists, kConformGenerating };
struct Conform {
ConformState state;
@@ -47,7 +44,10 @@ public:
*
* Thread-safe.
*/
Conform GetConformState(const QString &decoder_id, const QString &cache_path, const Decoder::CodecStream &stream, const AudioParams &params, bool wait);
Conform GetConformState(const QString &decoder_id,
const QString &cache_path,
const Decoder::CodecStream &stream,
const AudioParams &params, bool wait);
signals:
void ConformReady();
@@ -74,15 +74,17 @@ private:
/**
* @brief Get the destination filename of an audio stream conformed to a set of parameters
*/
static QVector<QString> GetConformedFilename(const QString &cache_path, const Decoder::CodecStream &stream, const AudioParams &params);
static QVector<QString>
GetConformedFilename(const QString &cache_path,
const Decoder::CodecStream &stream,
const AudioParams &params);
static bool AllConformsExist(const QVector<QString> &filenames);
private slots:
void ConformTaskFinished(Task *task, bool succeeded);
};
}
} // namespace olive
#endif // CONFORMMANAGER_H
+55 -25
View File
@@ -33,12 +33,13 @@
#include "node/project.h"
#include "task/taskmanager.h"
namespace olive {
namespace olive
{
const rational Decoder::kAnyTimecode = RATIONAL_MIN;
Decoder::Decoder() :
cached_texture_(nullptr)
Decoder::Decoder()
: cached_texture_(nullptr)
{
UpdateLastAccessed();
}
@@ -59,7 +60,8 @@ bool Decoder::Open(const CodecStream &stream)
if (stream_ == stream) {
return true;
} else {
qWarning() << "Tried to open a decoder that was already open with another stream";
qWarning()
<< "Tried to open a decoder that was already open with another stream";
return false;
}
} else {
@@ -84,7 +86,8 @@ bool Decoder::Open(const CodecStream &stream)
return true;
} else {
// Unset stream
qCritical() << "Failed to open" << stream_.filename() << "stream" << stream_.stream();
qCritical() << "Failed to open" << stream_.filename() << "stream"
<< stream_.stream();
CloseInternal();
stream_.Reset();
return false;
@@ -112,7 +115,8 @@ TexturePtr Decoder::RetrieveVideo(const RetrieveVideoParams &p)
return nullptr;
}
if (cached_texture_ && cached_time_ == p.time && cached_divider_ == p.divider) {
if (cached_texture_ && cached_time_ == p.time &&
cached_divider_ == p.divider) {
return cached_texture_;
}
@@ -123,7 +127,10 @@ TexturePtr Decoder::RetrieveVideo(const RetrieveVideoParams &p)
return cached_texture_;
}
Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, const AudioParams &params, const QString& cache_path, LoopMode loop_mode, RenderMode::Mode mode)
Decoder::RetrieveAudioStatus
Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range,
const AudioParams &params, const QString &cache_path,
LoopMode loop_mode, RenderMode::Mode mode)
{
QMutexLocker locker(&mutex_);
@@ -140,14 +147,17 @@ Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const Ti
}
// Get conform state from ConformManager
ConformManager::Conform conform = ConformManager::instance()->GetConformState(id(), cache_path, stream_, params, (mode == RenderMode::kOnline));
ConformManager::Conform conform =
ConformManager::instance()->GetConformState(
id(), cache_path, stream_, params, (mode == RenderMode::kOnline));
if (conform.state == ConformManager::kConformGenerating) {
// If we need the task, it's available in `conform.task`
return kWaitingForConform;
}
// See if we got the conform
if (RetrieveAudioFromConform(dest, conform.filenames, range, loop_mode, params)) {
if (RetrieveAudioFromConform(dest, conform.filenames, range, loop_mode,
params)) {
return kOK;
} else {
return kUnknownError;
@@ -175,7 +185,8 @@ void Decoder::Close()
}
}
bool Decoder::ConformAudio(const QVector<QString> &output_filenames, const AudioParams &params, CancelAtom *cancelled)
bool Decoder::ConformAudio(const QVector<QString> &output_filenames,
const AudioParams &params, CancelAtom *cancelled)
{
return ConformAudioInternal(output_filenames, params, cancelled);
}
@@ -217,11 +228,13 @@ DecoderPtr Decoder::CreateFromID(const QString &id)
void Decoder::SignalProcessingProgress(int64_t ts, int64_t duration)
{
if (duration != AV_NOPTS_VALUE && duration != 0) {
emit IndexProgress(static_cast<double>(ts) / static_cast<double>(duration));
emit IndexProgress(static_cast<double>(ts) /
static_cast<double>(duration));
}
}
QString Decoder::TransformImageSequenceFileName(const QString &filename, const int64_t& number)
QString Decoder::TransformImageSequenceFileName(const QString &filename,
const int64_t &number)
{
int digit_count = GetImageSequenceDigitCount(filename);
@@ -229,10 +242,13 @@ QString Decoder::TransformImageSequenceFileName(const QString &filename, const i
QString original_basename = file_info.completeBaseName();
QString new_basename = original_basename.left(original_basename.size() - digit_count)
.append(QStringLiteral("%1").arg(number, digit_count, 10, QChar('0')));
QString new_basename =
original_basename.left(original_basename.size() - digit_count)
.append(
QStringLiteral("%1").arg(number, digit_count, 10, QChar('0')));
return file_info.dir().filePath(file_info.fileName().replace(original_basename, new_basename));
return file_info.dir().filePath(
file_info.fileName().replace(original_basename, new_basename));
}
int Decoder::GetImageSequenceDigitCount(const QString &filename)
@@ -261,7 +277,8 @@ int64_t Decoder::GetImageSequenceIndex(const QString &filename)
QString original_basename = file_info.completeBaseName();
QString number_only = original_basename.mid(original_basename.size() - digit_count);
QString number_only =
original_basename.mid(original_basename.size() - digit_count);
return number_only.toLongLong();
}
@@ -272,7 +289,9 @@ TexturePtr Decoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
return nullptr;
}
bool Decoder::ConformAudioInternal(const QVector<QString> &filenames, const AudioParams &params, CancelAtom *cancelled)
bool Decoder::ConformAudioInternal(const QVector<QString> &filenames,
const AudioParams &params,
CancelAtom *cancelled)
{
Q_UNUSED(filenames)
Q_UNUSED(cancelled)
@@ -280,17 +299,22 @@ bool Decoder::ConformAudioInternal(const QVector<QString> &filenames, const Audi
return false;
}
bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, TimeRange range, LoopMode loop_mode, const AudioParams &input_params)
bool Decoder::RetrieveAudioFromConform(
SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames,
TimeRange range, LoopMode loop_mode, const AudioParams &input_params)
{
PlanarFileDevice input;
if (input.open(conform_filenames, QFile::ReadOnly)) {
// Offset range by audio start offset
range -= GetAudioStartOffset();
qint64 read_index = input_params.time_to_bytes(range.in()) / input_params.channel_count();
qint64 read_index = input_params.time_to_bytes(range.in()) /
input_params.channel_count();
qint64 write_index = 0;
const qint64 buffer_length_in_bytes = sample_buffer.sample_count() * input_params.bytes_per_sample_per_channel();
const qint64 buffer_length_in_bytes =
sample_buffer.sample_count() *
input_params.bytes_per_sample_per_channel();
while (write_index < buffer_length_in_bytes) {
if (loop_mode == LoopMode::kLoopModeLoop) {
@@ -308,15 +332,20 @@ bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVecto
if (read_index < 0) {
// Reading before 0, write silence here until audio data would actually start
write_count = qMin(-read_index, buffer_length_in_bytes);
sample_buffer.silence_bytes(write_index, write_index + write_count);
sample_buffer.silence_bytes(write_index,
write_index + write_count);
} else if (read_index >= input.size()) {
// Reading after data length, write silence until the end of the buffer
write_count = buffer_length_in_bytes - write_index;
sample_buffer.silence_bytes(write_index, write_index + write_count);
sample_buffer.silence_bytes(write_index,
write_index + write_count);
} else {
write_count = qMin(input.size() - read_index, buffer_length_in_bytes - write_index);
write_count = qMin(input.size() - read_index,
buffer_length_in_bytes - write_index);
input.seek(read_index);
input.read(reinterpret_cast<char**>(sample_buffer.to_raw_ptrs().data()), write_count, write_index);
input.read(reinterpret_cast<char **>(
sample_buffer.to_raw_ptrs().data()),
write_count, write_index);
}
read_index += write_count;
@@ -338,7 +367,8 @@ void Decoder::UpdateLastAccessed()
uint qHash(Decoder::CodecStream stream, uint seed)
{
return qHash(stream.filename(), seed) ^ ::qHash(stream.stream(), seed) ^ qHash(stream.block(), seed);
return qHash(stream.filename(), seed) ^ ::qHash(stream.stream(), seed) ^
qHash(stream.block(), seed);
}
}
+48 -31
View File
@@ -36,12 +36,17 @@ extern "C" {
#include "render/cancelatom.h"
#include "render/rendermodes.h"
namespace olive {
namespace olive
{
class Decoder;
using DecoderPtr = std::shared_ptr<Decoder>;
#define DECODER_DEFAULT_DESTRUCTOR(x) virtual ~x() override {CloseInternal();}
#define DECODER_DEFAULT_DESTRUCTOR(x) \
virtual ~x() override \
{ \
CloseInternal(); \
}
/**
* @brief A decoder's is the main class for bringing external media into Olive
@@ -59,15 +64,10 @@ using DecoderPtr = std::shared_ptr<Decoder>;
* A decoder does NOT perform any pixel/sample format conversion. Frames should pass through the PixelService
* to be utilized in the rest of the rendering pipeline.
*/
class Decoder : public QObject
{
class Decoder : public QObject {
Q_OBJECT
public:
enum RetrieveState {
kReady,
kFailedToOpen,
kIndexUnavailable
};
enum RetrieveState { kReady, kFailedToOpen, kIndexUnavailable };
Decoder();
@@ -76,24 +76,29 @@ public:
*/
virtual QString id() const = 0;
virtual bool SupportsVideo(){return false;}
virtual bool SupportsAudio(){return false;}
virtual bool SupportsVideo()
{
return false;
}
virtual bool SupportsAudio()
{
return false;
}
void IncrementAccessTime(qint64 t);
class CodecStream
{
class CodecStream {
public:
CodecStream() :
stream_(-1),
block_(nullptr)
CodecStream()
: stream_(-1)
, block_(nullptr)
{
}
CodecStream(const QString& filename, int stream, Block *block) :
filename_(filename),
stream_(stream),
block_(block)
CodecStream(const QString &filename, int stream, Block *block)
: filename_(filename)
, stream_(stream)
, block_(block)
{
}
@@ -138,7 +143,6 @@ public:
int stream_;
Block *block_;
};
/**
@@ -154,8 +158,7 @@ public:
static const rational kAnyTimecode;
struct RetrieveVideoParams
{
struct RetrieveVideoParams {
Renderer *renderer = nullptr;
rational time;
int divider = 1;
@@ -192,7 +195,10 @@ public:
*
* This function is thread safe and can only run while the decoder is open. \see Open()
*/
RetrieveAudioStatus RetrieveAudio(SampleBuffer &dest, const TimeRange& range, const AudioParams& params, const QString &cache_path, LoopMode loop_mode, RenderMode::Mode mode);
RetrieveAudioStatus
RetrieveAudio(SampleBuffer &dest, const TimeRange &range,
const AudioParams &params, const QString &cache_path,
LoopMode loop_mode, RenderMode::Mode mode);
/**
* @brief Determine the last time this decoder instance was used in any way
@@ -210,7 +216,8 @@ public:
*
* This function is re-entrant.
*/
virtual FootageDescription Probe(const QString& filename, CancelAtom *cancelled) const = 0;
virtual FootageDescription Probe(const QString &filename,
CancelAtom *cancelled) const = 0;
/**
* @brief Closes media/deallocates memory
@@ -222,7 +229,9 @@ public:
/**
* @brief Conform audio stream
*/
bool ConformAudio(const QVector<QString> &output_filenames, const AudioParams &params, CancelAtom *cancelled = nullptr);
bool ConformAudio(const QVector<QString> &output_filenames,
const AudioParams &params,
CancelAtom *cancelled = nullptr);
/**
* @brief Create a Decoder instance using a Decoder ID
@@ -233,7 +242,8 @@ public:
*/
static DecoderPtr CreateFromID(const QString &id);
static QString TransformImageSequenceFileName(const QString& filename, const int64_t& number);
static QString TransformImageSequenceFileName(const QString &filename,
const int64_t &number);
static int GetImageSequenceDigitCount(const QString &filename);
@@ -272,7 +282,9 @@ protected:
*/
virtual TexturePtr RetrieveVideoInternal(const RetrieveVideoParams &p);
virtual bool ConformAudioInternal(const QVector<QString>& filenames, const AudioParams &params, CancelAtom *cancelled);
virtual bool ConformAudioInternal(const QVector<QString> &filenames,
const AudioParams &params,
CancelAtom *cancelled);
void SignalProcessingProgress(int64_t ts, int64_t duration);
@@ -286,7 +298,10 @@ protected:
return stream_;
}
virtual rational GetAudioStartOffset() const { return 0; }
virtual rational GetAudioStartOffset() const
{
return 0;
}
signals:
/**
@@ -298,7 +313,10 @@ signals:
private:
void UpdateLastAccessed();
bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, TimeRange range, LoopMode loop_mode, const AudioParams &params);
bool RetrieveAudioFromConform(SampleBuffer &sample_buffer,
const QVector<QString> &conform_filenames,
TimeRange range, LoopMode loop_mode,
const AudioParams &params);
CodecStream stream_;
@@ -309,7 +327,6 @@ private:
TexturePtr cached_texture_;
rational cached_time_;
int cached_divider_;
};
uint qHash(Decoder::CodecStream stream, uint seed = 0);
+161 -85
View File
@@ -26,13 +26,16 @@
#include "ffmpeg/ffmpegencoder.h"
#include "oiio/oiioencoder.h"
namespace olive {
namespace olive
{
const QRegularExpression Encoder::kImageSequenceContainsDigits = QRegularExpression(QStringLiteral("\\[[#]+\\]"));
const QRegularExpression Encoder::kImageSequenceRemoveDigits = QRegularExpression(QStringLiteral("[\\-\\.\\ \\_]?\\[[#]+\\]"));
const QRegularExpression Encoder::kImageSequenceContainsDigits =
QRegularExpression(QStringLiteral("\\[[#]+\\]"));
const QRegularExpression Encoder::kImageSequenceRemoveDigits =
QRegularExpression(QStringLiteral("[\\-\\.\\ \\_]?\\[[#]+\\]"));
Encoder::Encoder(const EncodingParams &params) :
params_(params)
Encoder::Encoder(const EncodingParams &params)
: params_(params)
{
}
@@ -45,9 +48,11 @@ QString Encoder::GetFilenameForFrame(const rational &frame)
{
if (params().video_is_image_sequence()) {
// Transform!
int64_t frame_index = Timecode::time_to_timestamp(frame, params().video_params().frame_rate_as_time_base());
int64_t frame_index = Timecode::time_to_timestamp(
frame, params().video_params().frame_rate_as_time_base());
int digits = GetImageSequencePlaceholderDigitCount(params().filename());
QString frame_index_str = QStringLiteral("%1").arg(frame_index, digits, 10, QChar('0'));
QString frame_index_str =
QStringLiteral("%1").arg(frame_index, digits, 10, QChar('0'));
QString f = params_.filename();
f.replace(kImageSequenceContainsDigits, frame_index_str);
@@ -82,26 +87,27 @@ QString Encoder::FilenameRemoveDigitPlaceholder(QString filename)
return filename.remove(kImageSequenceRemoveDigits);
}
EncodingParams::EncodingParams() :
video_enabled_(false),
video_bit_rate_(0),
video_min_bit_rate_(0),
video_max_bit_rate_(0),
video_buffer_size_(0),
video_threads_(0),
video_is_image_sequence_(false),
audio_enabled_(false),
audio_bit_rate_(0),
subtitles_enabled_(false),
subtitles_are_sidecar_(false),
video_scaling_method_(kStretch),
has_custom_range_(false)
EncodingParams::EncodingParams()
: video_enabled_(false)
, video_bit_rate_(0)
, video_min_bit_rate_(0)
, video_max_bit_rate_(0)
, video_buffer_size_(0)
, video_threads_(0)
, video_is_image_sequence_(false)
, audio_enabled_(false)
, audio_bit_rate_(0)
, subtitles_enabled_(false)
, subtitles_are_sidecar_(false)
, video_scaling_method_(kStretch)
, has_custom_range_(false)
{
}
QDir EncodingParams::GetPresetPath()
{
return QDir(FileFunctions::GetConfigurationLocation()).filePath(QStringLiteral("exportpresets"));
return QDir(FileFunctions::GetConfigurationLocation())
.filePath(QStringLiteral("exportpresets"));
}
QStringList EncodingParams::GetListOfPresets()
@@ -110,14 +116,16 @@ QStringList EncodingParams::GetListOfPresets()
return d.entryList(QDir::Files);
}
void EncodingParams::EnableVideo(const VideoParams &video_params, const ExportCodec::Codec &vcodec)
void EncodingParams::EnableVideo(const VideoParams &video_params,
const ExportCodec::Codec &vcodec)
{
video_enabled_ = true;
video_params_ = video_params;
video_codec_ = vcodec;
}
void EncodingParams::EnableAudio(const AudioParams &audio_params, const ExportCodec::Codec &acodec)
void EncodingParams::EnableAudio(const AudioParams &audio_params,
const ExportCodec::Codec &acodec)
{
audio_enabled_ = true;
audio_params_ = audio_params;
@@ -130,7 +138,8 @@ void EncodingParams::EnableSubtitles(const ExportCodec::Codec &scodec)
subtitles_codec_ = scodec;
}
void EncodingParams::EnableSidecarSubtitles(const ExportFormat::Format &sfmt, const ExportCodec::Codec &scodec)
void EncodingParams::EnableSidecarSubtitles(const ExportFormat::Format &sfmt,
const ExportCodec::Codec &scodec)
{
subtitles_enabled_ = true;
subtitles_are_sidecar_ = true;
@@ -159,7 +168,8 @@ bool EncodingParams::Load(QXmlStreamReader *reader)
if (reader->name() == QStringLiteral("export")) {
int version = 0;
XMLAttributeLoop(reader, attr) {
XMLAttributeLoop(reader, attr)
{
if (attr.name() == QStringLiteral("version")) {
version = attr.value().toInt();
}
@@ -195,46 +205,73 @@ void EncodingParams::Save(QXmlStreamWriter *writer) const
writer->writeStartElement(QStringLiteral("export"));
writer->writeAttribute(QStringLiteral("version"), QString::number(kEncoderParamsVersion));
writer->writeAttribute(QStringLiteral("version"),
QString::number(kEncoderParamsVersion));
writer->writeTextElement(QStringLiteral("filename"), filename_);
writer->writeTextElement(QStringLiteral("format"), QString::number(format_));
writer->writeTextElement(QStringLiteral("format"),
QString::number(format_));
writer->writeTextElement(QStringLiteral("range"), QString::number(has_custom_range_));
writer->writeTextElement(QStringLiteral("customrangein"), QString::fromStdString(custom_range_.in().toString()));
writer->writeTextElement(QStringLiteral("customrangeout"), QString::fromStdString(custom_range_.out().toString()));
writer->writeTextElement(QStringLiteral("range"),
QString::number(has_custom_range_));
writer->writeTextElement(
QStringLiteral("customrangein"),
QString::fromStdString(custom_range_.in().toString()));
writer->writeTextElement(
QStringLiteral("customrangeout"),
QString::fromStdString(custom_range_.out().toString()));
writer->writeStartElement(QStringLiteral("video"));
writer->writeAttribute(QStringLiteral("enabled"), QString::number(video_enabled_));
writer->writeAttribute(QStringLiteral("enabled"),
QString::number(video_enabled_));
if (video_enabled_) {
writer->writeTextElement(QStringLiteral("codec"), QString::number(video_codec_));
writer->writeTextElement(QStringLiteral("width"), QString::number(video_params_.width()));
writer->writeTextElement(QStringLiteral("height"), QString::number(video_params_.height()));
writer->writeTextElement(QStringLiteral("format"), QString::number(video_params_.format()));
writer->writeTextElement(QStringLiteral("pixelaspect"), QString::fromStdString(video_params_.pixel_aspect_ratio().toString()));
writer->writeTextElement(QStringLiteral("timebase"), QString::fromStdString(video_params_.time_base().toString()));
writer->writeTextElement(QStringLiteral("divider"), QString::number(video_params_.divider()));
writer->writeTextElement(QStringLiteral("bitrate"), QString::number(video_bit_rate_));
writer->writeTextElement(QStringLiteral("minbitrate"), QString::number(video_min_bit_rate_));
writer->writeTextElement(QStringLiteral("maxbitrate"), QString::number(video_max_bit_rate_));
writer->writeTextElement(QStringLiteral("bufsize"), QString::number(video_buffer_size_));
writer->writeTextElement(QStringLiteral("threads"), QString::number(video_threads_));
writer->writeTextElement(QStringLiteral("codec"),
QString::number(video_codec_));
writer->writeTextElement(QStringLiteral("width"),
QString::number(video_params_.width()));
writer->writeTextElement(QStringLiteral("height"),
QString::number(video_params_.height()));
writer->writeTextElement(QStringLiteral("format"),
QString::number(video_params_.format()));
writer->writeTextElement(
QStringLiteral("pixelaspect"),
QString::fromStdString(
video_params_.pixel_aspect_ratio().toString()));
writer->writeTextElement(
QStringLiteral("timebase"),
QString::fromStdString(video_params_.time_base().toString()));
writer->writeTextElement(QStringLiteral("divider"),
QString::number(video_params_.divider()));
writer->writeTextElement(QStringLiteral("bitrate"),
QString::number(video_bit_rate_));
writer->writeTextElement(QStringLiteral("minbitrate"),
QString::number(video_min_bit_rate_));
writer->writeTextElement(QStringLiteral("maxbitrate"),
QString::number(video_max_bit_rate_));
writer->writeTextElement(QStringLiteral("bufsize"),
QString::number(video_buffer_size_));
writer->writeTextElement(QStringLiteral("threads"),
QString::number(video_threads_));
writer->writeTextElement(QStringLiteral("pixfmt"), video_pix_fmt_);
writer->writeTextElement(QStringLiteral("imgseq"), QString::number(video_is_image_sequence_));
writer->writeTextElement(QStringLiteral("imgseq"),
QString::number(video_is_image_sequence_));
writer->writeStartElement(QStringLiteral("color"));
writer->writeTextElement(QStringLiteral("output"), color_transform_.output());
writer->writeTextElement(QStringLiteral("output"),
color_transform_.output());
writer->writeEndElement(); // colortransform
writer->writeTextElement(QStringLiteral("vscale"), QString::number(video_scaling_method_));
writer->writeTextElement(QStringLiteral("vscale"),
QString::number(video_scaling_method_));
if (!video_opts_.isEmpty()) {
writer->writeStartElement(QStringLiteral("opts"));
QHash<QString, QString>::const_iterator i;
for (i=video_opts_.constBegin(); i!=video_opts_.constEnd(); i++) {
for (i = video_opts_.constBegin(); i != video_opts_.constEnd();
i++) {
writer->writeStartElement(QStringLiteral("entry"));
writer->writeTextElement(QStringLiteral("key"), i.key());
@@ -251,27 +288,38 @@ void EncodingParams::Save(QXmlStreamWriter *writer) const
writer->writeStartElement(QStringLiteral("audio"));
writer->writeAttribute(QStringLiteral("enabled"), QString::number(audio_enabled_));
writer->writeAttribute(QStringLiteral("enabled"),
QString::number(audio_enabled_));
if (audio_enabled_) {
writer->writeTextElement(QStringLiteral("codec"), QString::number(audio_codec_));
writer->writeTextElement(QStringLiteral("samplerate"), QString::number(audio_params_.sample_rate()));
writer->writeTextElement(QStringLiteral("codec"),
QString::number(audio_codec_));
writer->writeTextElement(QStringLiteral("samplerate"),
QString::number(audio_params_.sample_rate()));
writer->writeTextElement(QStringLiteral("channellayout"),
writer->writeTextElement(
QStringLiteral("channellayout"),
QString::number(audio_params().channel_layout().u.mask));
writer->writeTextElement(QStringLiteral("format"), QString::fromStdString(audio_params_.format().to_string()));
writer->writeTextElement(QStringLiteral("bitrate"), QString::number(audio_bit_rate_));
writer->writeTextElement(
QStringLiteral("format"),
QString::fromStdString(audio_params_.format().to_string()));
writer->writeTextElement(QStringLiteral("bitrate"),
QString::number(audio_bit_rate_));
}
writer->writeStartElement(QStringLiteral("subtitles"));
writer->writeAttribute(QStringLiteral("enabled"), QString::number(subtitles_enabled_));
writer->writeAttribute(QStringLiteral("enabled"),
QString::number(subtitles_enabled_));
if (subtitles_enabled_) {
writer->writeTextElement(QStringLiteral("sidecar"), QString::number(subtitles_are_sidecar_));
writer->writeTextElement(QStringLiteral("sidecarformat"), QString::number(subtitle_sidecar_fmt_));
writer->writeTextElement(QStringLiteral("sidecar"),
QString::number(subtitles_are_sidecar_));
writer->writeTextElement(QStringLiteral("sidecarformat"),
QString::number(subtitle_sidecar_fmt_));
writer->writeTextElement(QStringLiteral("codec"), QString::number(subtitles_codec_));
writer->writeTextElement(QStringLiteral("codec"),
QString::number(subtitles_codec_));
}
writer->writeEndElement(); // subtitles
@@ -324,7 +372,8 @@ Encoder::Type Encoder::GetTypeFromFormat(ExportFormat::Format f)
return kEncoderTypeNone;
}
Encoder *Encoder::CreateFromFormat(ExportFormat::Format f, const EncodingParams &params)
Encoder *Encoder::CreateFromFormat(ExportFormat::Format f,
const EncodingParams &params)
{
return CreateFromID(GetTypeFromFormat(f), params);
}
@@ -339,12 +388,14 @@ QStringList Encoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const
return QStringList();
}
std::vector<SampleFormat> Encoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
std::vector<SampleFormat>
Encoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
{
return std::vector<SampleFormat>();
}
QMatrix4x4 EncodingParams::GenerateMatrix(EncodingParams::VideoScalingMethod method,
QMatrix4x4
EncodingParams::GenerateMatrix(EncodingParams::VideoScalingMethod method,
int source_width, int source_height,
int dest_width, int dest_height)
{
@@ -354,8 +405,10 @@ QMatrix4x4 EncodingParams::GenerateMatrix(EncodingParams::VideoScalingMethod met
return preview_matrix;
}
float export_ar = static_cast<float>(dest_width) / static_cast<float>(dest_height);
float source_ar = static_cast<float>(source_width) / static_cast<float>(source_height);
float export_ar =
static_cast<float>(dest_width) / static_cast<float>(dest_height);
float source_ar =
static_cast<float>(source_width) / static_cast<float>(source_height);
if (qFuzzyCompare(export_ar, source_ar)) {
return preview_matrix;
@@ -378,15 +431,19 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
if (reader->name() == QStringLiteral("filename")) {
filename_ = reader->readElementText();
} else if (reader->name() == QStringLiteral("format")) {
format_ = static_cast<ExportFormat::Format>(reader->readElementText().toInt());
format_ = static_cast<ExportFormat::Format>(
reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("range")) {
has_custom_range_ = reader->readElementText().toInt();
} else if (reader->name() == QStringLiteral("customrangein")) {
custom_range_in = rational::fromString(reader->readElementText().toStdString());
custom_range_in =
rational::fromString(reader->readElementText().toStdString());
} else if (reader->name() == QStringLiteral("customrangeout")) {
custom_range_out = rational::fromString(reader->readElementText().toStdString());
custom_range_out =
rational::fromString(reader->readElementText().toStdString());
} else if (reader->name() == QStringLiteral("video")) {
XMLAttributeLoop(reader, attr) {
XMLAttributeLoop(reader, attr)
{
if (attr.name() == QStringLiteral("enabled")) {
video_enabled_ = attr.value().toInt();
}
@@ -394,25 +451,32 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("codec")) {
video_codec_ = static_cast<ExportCodec::Codec>(reader->readElementText().toInt());
video_codec_ = static_cast<ExportCodec::Codec>(
reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("width")) {
video_params_.set_width(reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("height")) {
video_params_.set_height(reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("format")) {
video_params_.set_format(static_cast<PixelFormat::Format>(reader->readElementText().toInt()));
video_params_.set_format(static_cast<PixelFormat::Format>(
reader->readElementText().toInt()));
} else if (reader->name() == QStringLiteral("pixelaspect")) {
video_params_.set_pixel_aspect_ratio(rational::fromString(reader->readElementText().toStdString()));
video_params_.set_pixel_aspect_ratio(rational::fromString(
reader->readElementText().toStdString()));
} else if (reader->name() == QStringLiteral("timebase")) {
video_params_.set_time_base(rational::fromString(reader->readElementText().toStdString()));
video_params_.set_time_base(rational::fromString(
reader->readElementText().toStdString()));
} else if (reader->name() == QStringLiteral("divider")) {
video_params_.set_divider(reader->readElementText().toInt());
video_params_.set_divider(
reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("bitrate")) {
video_bit_rate_ = reader->readElementText().toLongLong();
} else if (reader->name() == QStringLiteral("minbitrate")) {
video_min_bit_rate_ = reader->readElementText().toLongLong();
video_min_bit_rate_ =
reader->readElementText().toLongLong();
} else if (reader->name() == QStringLiteral("maxbitrate")) {
video_max_bit_rate_ = reader->readElementText().toLongLong();
video_max_bit_rate_ =
reader->readElementText().toLongLong();
} else if (reader->name() == QStringLiteral("bufsize")) {
video_buffer_size_ = reader->readElementText().toLongLong();
} else if (reader->name() == QStringLiteral("threads")) {
@@ -420,7 +484,8 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
} else if (reader->name() == QStringLiteral("pixfmt")) {
video_pix_fmt_ = reader->readElementText();
} else if (reader->name() == QStringLiteral("imgseq")) {
video_is_image_sequence_ = reader->readElementText().toInt();
video_is_image_sequence_ =
reader->readElementText().toInt();
} else if (reader->name() == QStringLiteral("color")) {
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("output")) {
@@ -430,7 +495,8 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
}
}
} else if (reader->name() == QStringLiteral("vscale")) {
video_scaling_method_ = static_cast<VideoScalingMethod>(reader->readElementText().toInt());
video_scaling_method_ = static_cast<VideoScalingMethod>(
reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("opts")) {
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("entry")) {
@@ -438,7 +504,8 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("key")) {
key = reader->readElementText();
} else if (reader->name() == QStringLiteral("value")) {
} else if (reader->name() ==
QStringLiteral("value")) {
value = reader->readElementText();
} else {
reader->skipCurrentElement();
@@ -459,7 +526,8 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
video_params_.set_pixel_aspect_ratio(1);
}
} else if (reader->name() == QStringLiteral("audio")) {
XMLAttributeLoop(reader, attr) {
XMLAttributeLoop(reader, attr)
{
if (attr.name() == QStringLiteral("enabled")) {
audio_enabled_ = attr.value().toInt();
}
@@ -467,16 +535,21 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
while (XMLReadNextStartElement(reader)) {
if (reader->name() == QStringLiteral("codec")) {
audio_codec_ = static_cast<ExportCodec::Codec>(reader->readElementText().toInt());
audio_codec_ = static_cast<ExportCodec::Codec>(
reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("samplerate")) {
audio_params_.set_sample_rate(reader->readElementText().toInt());
audio_params_.set_sample_rate(
reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("channellayout")) {
AVChannelLayout av_channel_layout;
av_channel_layout_from_mask(&av_channel_layout, reader->readElementText().toLongLong());
av_channel_layout_from_mask(
&av_channel_layout,
reader->readElementText().toLongLong());
audio_params_.set_channel_layout(av_channel_layout);
av_channel_layout_uninit(&av_channel_layout);
} else if (reader->name() == QStringLiteral("format")) {
audio_params_.set_format(SampleFormat::from_string(reader->readElementText().toStdString()));
audio_params_.set_format(SampleFormat::from_string(
reader->readElementText().toStdString()));
} else if (reader->name() == QStringLiteral("bitrate")) {
audio_bit_rate_ = reader->readElementText().toLongLong();
} else {
@@ -489,7 +562,8 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
audio_bit_rate_ = 320000;
}
} else if (reader->name() == QStringLiteral("subtitles")) {
XMLAttributeLoop(reader, attr) {
XMLAttributeLoop(reader, attr)
{
if (attr.name() == QStringLiteral("enabled")) {
subtitles_enabled_ = attr.value().toInt();
}
@@ -499,9 +573,11 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
if (reader->name() == QStringLiteral("sidecar")) {
subtitles_are_sidecar_ = reader->readElementText().toInt();
} else if (reader->name() == QStringLiteral("sidecarformat")) {
subtitle_sidecar_fmt_ = static_cast<ExportFormat::Format>(reader->readElementText().toInt());
subtitle_sidecar_fmt_ = static_cast<ExportFormat::Format>(
reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("codec")) {
subtitles_codec_ = static_cast<ExportCodec::Codec>(reader->readElementText().toInt());
subtitles_codec_ = static_cast<ExportCodec::Codec>(
reader->readElementText().toInt());
} else {
reader->skipCurrentElement();
}
+187 -65
View File
@@ -34,19 +34,15 @@
#include "render/subtitleparams.h"
#include "render/videoparams.h"
//这个代码也许是导出编码视频用的?
namespace olive {
namespace olive
{
class Encoder;
using EncoderPtr = std::shared_ptr<Encoder>;
class EncodingParams
{
class EncodingParams {
public:
enum VideoScalingMethod {
kFit,
kStretch,
kCrop
};
enum VideoScalingMethod { kFit, kStretch, kCrop };
EncodingParams();
@@ -58,61 +54,178 @@ public:
return video_enabled_ || audio_enabled_ || subtitles_enabled_;
}
void SetFilename(const QString& filename) { filename_ = filename; }
void SetFilename(const QString &filename)
{
filename_ = filename;
}
void EnableVideo(const VideoParams& video_params, const ExportCodec::Codec& vcodec);
void EnableAudio(const AudioParams& audio_params, const ExportCodec::Codec &acodec);
void EnableVideo(const VideoParams &video_params,
const ExportCodec::Codec &vcodec);
void EnableAudio(const AudioParams &audio_params,
const ExportCodec::Codec &acodec);
void EnableSubtitles(const ExportCodec::Codec &scodec);
void EnableSidecarSubtitles(const ExportFormat::Format &sfmt, const ExportCodec::Codec &scodec);
void EnableSidecarSubtitles(const ExportFormat::Format &sfmt,
const ExportCodec::Codec &scodec);
void DisableVideo();
void DisableAudio();
void DisableSubtitles();
const ExportFormat::Format &format() const { return format_; }
void set_format(const ExportFormat::Format &format) { format_ = format; }
const ExportFormat::Format &format() const
{
return format_;
}
void set_format(const ExportFormat::Format &format)
{
format_ = format;
}
void set_video_option(const QString& key, const QString& value) { video_opts_.insert(key, value); }
void set_video_bit_rate(const int64_t& rate) { video_bit_rate_ = rate; }
void set_video_min_bit_rate(const int64_t& rate) { video_min_bit_rate_ = rate; }
void set_video_max_bit_rate(const int64_t& rate) { video_max_bit_rate_ = rate; }
void set_video_buffer_size(const int64_t& sz) { video_buffer_size_ = sz; }
void set_video_threads(const int& threads) { video_threads_ = threads; }
void set_video_pix_fmt(const QString& s) { video_pix_fmt_ = s; }
void set_video_is_image_sequence(bool s) { video_is_image_sequence_ = s; }
void set_color_transform(const ColorTransform& color_transform) { color_transform_ = color_transform; }
void set_video_option(const QString &key, const QString &value)
{
video_opts_.insert(key, value);
}
void set_video_bit_rate(const int64_t &rate)
{
video_bit_rate_ = rate;
}
void set_video_min_bit_rate(const int64_t &rate)
{
video_min_bit_rate_ = rate;
}
void set_video_max_bit_rate(const int64_t &rate)
{
video_max_bit_rate_ = rate;
}
void set_video_buffer_size(const int64_t &sz)
{
video_buffer_size_ = sz;
}
void set_video_threads(const int &threads)
{
video_threads_ = threads;
}
void set_video_pix_fmt(const QString &s)
{
video_pix_fmt_ = s;
}
void set_video_is_image_sequence(bool s)
{
video_is_image_sequence_ = s;
}
void set_color_transform(const ColorTransform &color_transform)
{
color_transform_ = color_transform;
}
const QString& filename() const { return filename_; }
const QString &filename() const
{
return filename_;
}
bool video_enabled() const { return video_enabled_; }
const ExportCodec::Codec& video_codec() const { return video_codec_; }
const VideoParams& video_params() const { return video_params_; }
const QHash<QString, QString>& video_opts() const { return video_opts_; }
QString video_option(const QString &key) const { return video_opts_.value(key); }
bool has_video_opt(const QString &key) const { return video_opts_.contains(key); }
const int64_t& video_bit_rate() const { return video_bit_rate_; }
const int64_t& video_min_bit_rate() const { return video_min_bit_rate_; }
const int64_t& video_max_bit_rate() const { return video_max_bit_rate_; }
const int64_t& video_buffer_size() const { return video_buffer_size_; }
const int& video_threads() const { return video_threads_; }
const QString& video_pix_fmt() const { return video_pix_fmt_; }
bool video_is_image_sequence() const { return video_is_image_sequence_; }
const ColorTransform& color_transform() const { return color_transform_; }
bool video_enabled() const
{
return video_enabled_;
}
const ExportCodec::Codec &video_codec() const
{
return video_codec_;
}
const VideoParams &video_params() const
{
return video_params_;
}
const QHash<QString, QString> &video_opts() const
{
return video_opts_;
}
QString video_option(const QString &key) const
{
return video_opts_.value(key);
}
bool has_video_opt(const QString &key) const
{
return video_opts_.contains(key);
}
const int64_t &video_bit_rate() const
{
return video_bit_rate_;
}
const int64_t &video_min_bit_rate() const
{
return video_min_bit_rate_;
}
const int64_t &video_max_bit_rate() const
{
return video_max_bit_rate_;
}
const int64_t &video_buffer_size() const
{
return video_buffer_size_;
}
const int &video_threads() const
{
return video_threads_;
}
const QString &video_pix_fmt() const
{
return video_pix_fmt_;
}
bool video_is_image_sequence() const
{
return video_is_image_sequence_;
}
const ColorTransform &color_transform() const
{
return color_transform_;
}
bool audio_enabled() const { return audio_enabled_; }
const ExportCodec::Codec &audio_codec() const { return audio_codec_; }
const AudioParams& audio_params() const { return audio_params_; }
const int64_t& audio_bit_rate() const { return audio_bit_rate_; }
bool audio_enabled() const
{
return audio_enabled_;
}
const ExportCodec::Codec &audio_codec() const
{
return audio_codec_;
}
const AudioParams &audio_params() const
{
return audio_params_;
}
const int64_t &audio_bit_rate() const
{
return audio_bit_rate_;
}
void set_audio_bit_rate(const int64_t& b) { audio_bit_rate_ = b; }
void set_audio_bit_rate(const int64_t &b)
{
audio_bit_rate_ = b;
}
bool subtitles_enabled() const { return subtitles_enabled_; }
bool subtitles_are_sidecar() const { return subtitles_are_sidecar_; }
ExportFormat::Format subtitle_sidecar_fmt() const { return subtitle_sidecar_fmt_; }
ExportCodec::Codec subtitles_codec() const { return subtitles_codec_; }
bool subtitles_enabled() const
{
return subtitles_enabled_;
}
bool subtitles_are_sidecar() const
{
return subtitles_are_sidecar_;
}
ExportFormat::Format subtitle_sidecar_fmt() const
{
return subtitle_sidecar_fmt_;
}
ExportCodec::Codec subtitles_codec() const
{
return subtitles_codec_;
}
const rational& GetExportLength() const { return export_length_; }
void SetExportLength(const rational& export_length) { export_length_ = export_length; }
const rational &GetExportLength() const
{
return export_length_;
}
void SetExportLength(const rational &export_length)
{
export_length_ = export_length;
}
bool Load(QIODevice *device);
bool Load(QXmlStreamReader *reader);
@@ -120,16 +233,29 @@ public:
void Save(QIODevice *device) const;
void Save(QXmlStreamWriter *writer) const;
bool has_custom_range() const { return has_custom_range_; }
const TimeRange& custom_range() const { return custom_range_; }
bool has_custom_range() const
{
return has_custom_range_;
}
const TimeRange &custom_range() const
{
return custom_range_;
}
void set_custom_range(const TimeRange &custom_range)
{
has_custom_range_ = true;
custom_range_ = custom_range;
}
const VideoScalingMethod& video_scaling_method() const { return video_scaling_method_; }
void set_video_scaling_method(const VideoScalingMethod& video_scaling_method) { video_scaling_method_ = video_scaling_method; }
const VideoScalingMethod &video_scaling_method() const
{
return video_scaling_method_;
}
void
set_video_scaling_method(const VideoScalingMethod &video_scaling_method)
{
video_scaling_method_ = video_scaling_method;
}
static QMatrix4x4 GenerateMatrix(VideoScalingMethod method,
int source_width, int source_height,
@@ -171,20 +297,14 @@ private:
bool has_custom_range_;
TimeRange custom_range_;
};
class Encoder : public QObject
{
class Encoder : public QObject {
Q_OBJECT
public:
Encoder(const EncodingParams &params);
enum Type {
kEncoderTypeNone = -1,
kEncoderTypeFFmpeg,
kEncoderTypeOIIO
};
enum Type { kEncoderTypeNone = -1, kEncoderTypeFFmpeg, kEncoderTypeOIIO };
/**
* @brief Create a Encoder instance using a Encoder ID
@@ -197,12 +317,14 @@ public:
static Type GetTypeFromFormat(ExportFormat::Format f);
static Encoder *CreateFromFormat(ExportFormat::Format f, const EncodingParams &params);
static Encoder *CreateFromFormat(ExportFormat::Format f,
const EncodingParams &params);
static Encoder *CreateFromParams(const EncodingParams &params);
virtual QStringList GetPixelFormatsForCodec(ExportCodec::Codec c) const;
virtual std::vector<SampleFormat> GetSampleFormatsForCodec(ExportCodec::Codec c) const;
virtual std::vector<SampleFormat>
GetSampleFormatsForCodec(ExportCodec::Codec c) const;
const EncodingParams &params() const;
@@ -229,7 +351,8 @@ public:
public slots:
virtual bool Open() = 0;
virtual bool WriteFrame(olive::FramePtr frame, olive::core::rational time) = 0;
virtual bool WriteFrame(olive::FramePtr frame,
olive::core::rational time) = 0;
virtual bool WriteAudio(const olive::SampleBuffer &audio) = 0;
virtual bool WriteSubtitle(const SubtitleBlock *sub_block) = 0;
@@ -245,7 +368,6 @@ private:
EncodingParams params_;
QString error_;
};
}
+2 -1
View File
@@ -25,7 +25,8 @@ extern "C" {
#include <libavutil/pixdesc.h>
}
namespace olive {
namespace olive
{
QString ExportCodec::GetCodecName(ExportCodec::Codec c)
{
+3 -4
View File
@@ -27,10 +27,10 @@
#include "common/define.h"
#include "render/subtitleparams.h"
namespace olive {
class ExportCodec : public QObject
namespace olive
{
class ExportCodec : public QObject {
Q_OBJECT
public:
// Only append to this list (never insert) because indexes are used in serialized files
@@ -63,7 +63,6 @@ public:
static bool IsCodecAStillImage(Codec c);
static bool IsCodecLossless(Codec c);
};
}
+26 -13
View File
@@ -22,7 +22,8 @@
#include "encoder.h"
namespace olive {
namespace olive
{
QString ExportFormat::GetName(olive::ExportFormat::Format f)
{
@@ -111,9 +112,11 @@ QList<ExportCodec::Codec> ExportFormat::GetVideoCodecs(ExportFormat::Format f)
case kFormatDNxHD:
return { ExportCodec::kCodecDNxHD };
case kFormatMatroska:
return {ExportCodec::kCodecH264, ExportCodec::kCodecH264rgb, ExportCodec::kCodecH265, ExportCodec::kCodecVP9};
return { ExportCodec::kCodecH264, ExportCodec::kCodecH264rgb,
ExportCodec::kCodecH265, ExportCodec::kCodecVP9 };
case kFormatMPEG4Video:
return {ExportCodec::kCodecH264, ExportCodec::kCodecH264rgb, ExportCodec::kCodecH265};
return { ExportCodec::kCodecH264, ExportCodec::kCodecH264rgb,
ExportCodec::kCodecH265 };
case kFormatOpenEXR:
return { ExportCodec::kCodecOpenEXR };
case kFormatPNG:
@@ -121,7 +124,9 @@ QList<ExportCodec::Codec> ExportFormat::GetVideoCodecs(ExportFormat::Format f)
case kFormatTIFF:
return { ExportCodec::kCodecTIFF };
case kFormatQuickTime:
return {ExportCodec::kCodecH264, ExportCodec::kCodecH264rgb, ExportCodec::kCodecH265, ExportCodec::kCodecProRes, ExportCodec::kCodecCineform};
return { ExportCodec::kCodecH264, ExportCodec::kCodecH264rgb,
ExportCodec::kCodecH265, ExportCodec::kCodecProRes,
ExportCodec::kCodecCineform };
case kFormatWebM:
return { ExportCodec::kCodecAV1, ExportCodec::kCodecVP9 };
case kFormatOgg:
@@ -145,14 +150,21 @@ QList<ExportCodec::Codec> ExportFormat::GetAudioCodecs(ExportFormat::Format f)
case kFormatDNxHD:
return { ExportCodec::kCodecPCM };
case kFormatMatroska:
return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM, ExportCodec::kCodecVorbis, ExportCodec::kCodecOpus, ExportCodec::kCodecFLAC};
return { ExportCodec::kCodecAAC, ExportCodec::kCodecMP2,
ExportCodec::kCodecMP3, ExportCodec::kCodecPCM,
ExportCodec::kCodecVorbis, ExportCodec::kCodecOpus,
ExportCodec::kCodecFLAC };
case kFormatMPEG4Video:
case kFormatMPEG4Audio:
return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3};
return { ExportCodec::kCodecAAC, ExportCodec::kCodecMP2,
ExportCodec::kCodecMP3 };
case kFormatQuickTime:
return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM};
return { ExportCodec::kCodecAAC, ExportCodec::kCodecMP2,
ExportCodec::kCodecMP3, ExportCodec::kCodecPCM };
case kFormatWebM:
return {ExportCodec::kCodecOpus, ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM, ExportCodec::kCodecVorbis};
return { ExportCodec::kCodecOpus, ExportCodec::kCodecAAC,
ExportCodec::kCodecMP2, ExportCodec::kCodecMP3,
ExportCodec::kCodecPCM, ExportCodec::kCodecVorbis };
// Audio only formats
case kFormatWAV:
@@ -164,7 +176,8 @@ QList<ExportCodec::Codec> ExportFormat::GetAudioCodecs(ExportFormat::Format f)
case kFormatFLAC:
return { ExportCodec::kCodecFLAC };
case kFormatOgg:
return {ExportCodec::kCodecOpus, ExportCodec::kCodecVorbis, ExportCodec::kCodecPCM};
return { ExportCodec::kCodecOpus, ExportCodec::kCodecVorbis,
ExportCodec::kCodecPCM };
// Video only formats
case kFormatOpenEXR:
@@ -173,7 +186,6 @@ QList<ExportCodec::Codec> ExportFormat::GetAudioCodecs(ExportFormat::Format f)
case kFormatSRT:
case kFormatCount:
break;
}
return {};
@@ -205,7 +217,8 @@ QList<ExportCodec::Codec> ExportFormat::GetSubtitleCodecs(Format f)
return {};
}
QStringList ExportFormat::GetPixelFormatsForCodec(ExportFormat::Format f, ExportCodec::Codec c)
QStringList ExportFormat::GetPixelFormatsForCodec(ExportFormat::Format f,
ExportCodec::Codec c)
{
Encoder *e = Encoder::CreateFromFormat(f, EncodingParams());
QStringList list;
@@ -218,7 +231,8 @@ QStringList ExportFormat::GetPixelFormatsForCodec(ExportFormat::Format f, Export
return list;
}
std::vector<SampleFormat> ExportFormat::GetSampleFormatsForCodec(Format format, ExportCodec::Codec c)
std::vector<SampleFormat>
ExportFormat::GetSampleFormatsForCodec(Format format, ExportCodec::Codec c)
{
std::vector<SampleFormat> f;
Encoder *e = Encoder::CreateFromFormat(format, EncodingParams());
@@ -228,7 +242,6 @@ std::vector<SampleFormat> ExportFormat::GetSampleFormatsForCodec(Format format,
delete e;
}
return f;
}
+5 -5
View File
@@ -27,10 +27,10 @@
#include "common/define.h"
#include "exportcodec.h"
namespace olive {
class ExportFormat : public QObject
namespace olive
{
class ExportFormat : public QObject {
Q_OBJECT
public:
// Only append to this list (never insert) because indexes are used in serialized files
@@ -61,8 +61,8 @@ public:
static QList<ExportCodec::Codec> GetSubtitleCodecs(ExportFormat::Format f);
static QStringList GetPixelFormatsForCodec(Format f, ExportCodec::Codec c);
static std::vector<SampleFormat> GetSampleFormatsForCodec(Format f, ExportCodec::Codec c);
static std::vector<SampleFormat>
GetSampleFormatsForCodec(Format f, ExportCodec::Codec c);
};
}
+251 -175
View File
@@ -45,16 +45,17 @@ extern "C" {
#include "render/renderer.h"
#include "render/subtitleparams.h"
namespace olive {
namespace olive
{
QVariant Yuv2RgbShader;
QVariant DeinterlaceShader;
FFmpegDecoder::FFmpegDecoder() :
sws_ctx_(nullptr),
working_packet_(nullptr),
cache_at_zero_(false),
cache_at_eof_(false)
FFmpegDecoder::FFmpegDecoder()
: sws_ctx_(nullptr)
, working_packet_(nullptr)
, cache_at_zero_(false)
, cache_at_eof_(false)
{
}
@@ -73,21 +74,22 @@ bool FFmpegDecoder::OpenInternal()
return false;
}
TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, const RetrieveVideoParams &p, const AVFramePtr original)
TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f,
const RetrieveVideoParams &p,
const AVFramePtr original)
{
// Determine native format
AVPixelFormat ideal_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(f->format));
AVPixelFormat ideal_fmt = FFmpegUtils::GetCompatiblePixelFormat(
static_cast<AVPixelFormat>(f->format));
PixelFormat native_fmt = GetNativePixelFormat(ideal_fmt);
int native_channels = GetNativeChannelCount(ideal_fmt);
// Set up video params
VideoParams vp(original->width,
original->height,
native_fmt,
VideoParams vp(original->width, original->height, native_fmt,
native_channels,
av_guess_sample_aspect_ratio(instance_.fmt_ctx(), instance_.avstream(), nullptr),
VideoParams::kInterlaceNone,
p.divider);
av_guess_sample_aspect_ratio(instance_.fmt_ctx(),
instance_.avstream(), nullptr),
VideoParams::kInterlaceNone, p.divider);
// Create texture
TexturePtr tex = p.renderer->CreateTexture(vp);
@@ -101,12 +103,13 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, const RetrieveVi
case AV_PIX_FMT_YUV444P10LE:
case AV_PIX_FMT_YUV420P12LE:
case AV_PIX_FMT_YUV422P12LE:
case AV_PIX_FMT_YUV444P12LE:
{
case AV_PIX_FMT_YUV444P12LE: {
// Run through YUV to RGB shader
if (Yuv2RgbShader.isNull()) {
// Compile shader
Yuv2RgbShader = p.renderer->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/yuv2rgb.frag"))));
Yuv2RgbShader = p.renderer->CreateNativeShader(
ShaderCode(FileFunctions::ReadFileAsString(
QStringLiteral(":/shaders/yuv2rgb.frag"))));
if (Yuv2RgbShader.isNull()) {
return nullptr;
}
@@ -142,7 +145,8 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, const RetrieveVi
plane_params.set_channel_count(1);
plane_params.set_format(native_fmt);
TexturePtr y_plane = p.renderer->CreateTexture(plane_params, hw_in->data[0], hw_in->linesize[0] / px_size);
TexturePtr y_plane = p.renderer->CreateTexture(
plane_params, hw_in->data[0], hw_in->linesize[0] / px_size);
switch (f->format) {
case AV_PIX_FMT_YUV420P:
@@ -163,21 +167,37 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, const RetrieveVi
break;
}
TexturePtr u_plane = p.renderer->CreateTexture(plane_params, hw_in->data[1], hw_in->linesize[1] / px_size);
TexturePtr v_plane = p.renderer->CreateTexture(plane_params, hw_in->data[2], hw_in->linesize[2] / px_size);
TexturePtr u_plane = p.renderer->CreateTexture(
plane_params, hw_in->data[1], hw_in->linesize[1] / px_size);
TexturePtr v_plane = p.renderer->CreateTexture(
plane_params, hw_in->data[2], hw_in->linesize[2] / px_size);
ShaderJob job;
job.Insert(QStringLiteral("y_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(y_plane)));
job.Insert(QStringLiteral("u_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(u_plane)));
job.Insert(QStringLiteral("v_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(v_plane)));
job.Insert(QStringLiteral("bits_per_pixel"), NodeValue(NodeValue::kInt, bits_per_pixel));
job.Insert(QStringLiteral("full_range"), NodeValue(NodeValue::kBoolean, hw_in->color_range == AVCOL_RANGE_JPEG));
job.Insert(QStringLiteral("y_channel"),
NodeValue(NodeValue::kTexture,
QVariant::fromValue(y_plane)));
job.Insert(QStringLiteral("u_channel"),
NodeValue(NodeValue::kTexture,
QVariant::fromValue(u_plane)));
job.Insert(QStringLiteral("v_channel"),
NodeValue(NodeValue::kTexture,
QVariant::fromValue(v_plane)));
job.Insert(QStringLiteral("bits_per_pixel"),
NodeValue(NodeValue::kInt, bits_per_pixel));
job.Insert(QStringLiteral("full_range"),
NodeValue(NodeValue::kBoolean,
hw_in->color_range == AVCOL_RANGE_JPEG));
const int *yuv_coeffs = sws_getCoefficients(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(hw_in->colorspace));
job.Insert(QStringLiteral("yuv_crv"), NodeValue(NodeValue::kFloat, yuv_coeffs[0]/65536.0));
job.Insert(QStringLiteral("yuv_cgu"), NodeValue(NodeValue::kFloat, yuv_coeffs[2]/65536.0));
job.Insert(QStringLiteral("yuv_cgv"), NodeValue(NodeValue::kFloat, yuv_coeffs[3]/65536.0));
job.Insert(QStringLiteral("yuv_cbu"), NodeValue(NodeValue::kFloat, yuv_coeffs[1]/65536.0));
const int *yuv_coeffs = sws_getCoefficients(
FFmpegUtils::GetSwsColorspaceFromAVColorSpace(hw_in->colorspace));
job.Insert(QStringLiteral("yuv_crv"),
NodeValue(NodeValue::kFloat, yuv_coeffs[0] / 65536.0));
job.Insert(QStringLiteral("yuv_cgu"),
NodeValue(NodeValue::kFloat, yuv_coeffs[2] / 65536.0));
job.Insert(QStringLiteral("yuv_cgv"),
NodeValue(NodeValue::kFloat, yuv_coeffs[3] / 65536.0));
job.Insert(QStringLiteral("yuv_cbu"),
NodeValue(NodeValue::kFloat, yuv_coeffs[1] / 65536.0));
tex = p.renderer->CreateTexture(vp);
p.renderer->BlitToTexture(Yuv2RgbShader, job, tex.get(), false);
@@ -194,13 +214,16 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, const RetrieveVi
if (p.src_interlacing != VideoParams::kInterlaceNone) {
if (DeinterlaceShader.isNull()) {
// Compile shader
DeinterlaceShader = p.renderer->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/deinterlace2.frag"))));
DeinterlaceShader = p.renderer->CreateNativeShader(
ShaderCode(FileFunctions::ReadFileAsString(
QStringLiteral(":/shaders/deinterlace2.frag"))));
if (DeinterlaceShader.isNull()) {
return nullptr;
}
}
rational frame_rate_tb = av_guess_frame_rate(instance_.fmt_ctx(), instance_.avstream(), original.get());
rational frame_rate_tb = av_guess_frame_rate(
instance_.fmt_ctx(), instance_.avstream(), original.get());
// Double frame rate for interlaced fields
frame_rate_tb *= 2;
@@ -208,22 +231,30 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, const RetrieveVi
// Flip frame rate so it can be used as a timebase
frame_rate_tb.flip();
int64_t req = Timecode::time_to_timestamp(p.time + rational(instance_.fmt_ctx()->start_time, AV_TIME_BASE), frame_rate_tb);
int64_t frm = Timecode::rescale_timestamp(original->pts, instance_.avstream()->time_base, frame_rate_tb);
int64_t req = Timecode::time_to_timestamp(
p.time + rational(instance_.fmt_ctx()->start_time, AV_TIME_BASE),
frame_rate_tb);
int64_t frm = Timecode::rescale_timestamp(
original->pts, instance_.avstream()->time_base, frame_rate_tb);
bool first = (req == frm);
bool top_first = (p.src_interlacing == VideoParams::kInterlacedTopFirst);
bool top_first =
(p.src_interlacing == VideoParams::kInterlacedTopFirst);
int interlacing = (first == top_first) ? 1 : 2;
TexturePtr deinterlaced = p.renderer->CreateTexture(tex->params());
ShaderJob job;
job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, tex));
job.Insert(QStringLiteral("interlacing"), NodeValue(NodeValue::kInt, interlacing));
job.Insert(QStringLiteral("pixel_height"), NodeValue(NodeValue::kInt, original->height));
job.Insert(QStringLiteral("ove_maintex"),
NodeValue(NodeValue::kTexture, tex));
job.Insert(QStringLiteral("interlacing"),
NodeValue(NodeValue::kInt, interlacing));
job.Insert(QStringLiteral("pixel_height"),
NodeValue(NodeValue::kInt, original->height));
p.renderer->BlitToTexture(DeinterlaceShader, job, deinterlaced.get(), false);
p.renderer->BlitToTexture(DeinterlaceShader, job, deinterlaced.get(),
false);
tex = deinterlaced;
}
@@ -241,10 +272,13 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
AVFramePtr original = f;
// Disregard "JPEG" pixel formats because we allow the user to override that
f->format = FFmpegUtils::ConvertJPEGSpaceToRegularSpace(static_cast<AVPixelFormat>(f->format));
f->format = FFmpegUtils::ConvertJPEGSpaceToRegularSpace(
static_cast<AVPixelFormat>(f->format));
// Force frame's color range to whatever it's set to in Olive
f->color_range = p.force_range == VideoParams::kColorRangeFull ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
f->color_range = p.force_range == VideoParams::kColorRangeFull ?
AVCOL_RANGE_JPEG :
AVCOL_RANGE_MPEG;
// Perform any CPU processing required
f = PreProcessFrame(f, p);
@@ -277,8 +311,10 @@ rational FFmpegDecoder::GetAudioStartOffset() const
{
auto f = instance_.fmt_ctx();
if (f) {
rational fmt_start = rational(instance_.fmt_ctx()->start_time, AV_TIME_BASE);
rational str_start = rational(instance_.avstream()->time_base) * instance_.avstream()->start_time;
rational fmt_start =
rational(instance_.fmt_ctx()->start_time, AV_TIME_BASE);
rational str_start = rational(instance_.avstream()->time_base) *
instance_.avstream()->start_time;
return str_start - fmt_start;
} else {
return 0;
@@ -290,7 +326,8 @@ QString FFmpegDecoder::id() const
return QStringLiteral("ffmpeg");
}
FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *cancelled) const
FootageDescription FFmpegDecoder::Probe(const QString &filename,
CancelAtom *cancelled) const
{
// Return value
FootageDescription desc(id());
@@ -307,41 +344,42 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
// Handle format context error
if (error_code == 0) {
// Retrieve metadata about the media
avformat_find_stream_info(fmt_ctx, nullptr);
int64_t footage_duration = fmt_ctx->duration;
bool duration_guessed_from_bitrate = (fmt_ctx->duration_estimation_method == AVFMT_DURATION_FROM_BITRATE);
bool duration_guessed_from_bitrate =
(fmt_ctx->duration_estimation_method ==
AVFMT_DURATION_FROM_BITRATE);
if (duration_guessed_from_bitrate) {
qWarning() << "Unreliable duration detected - we will manually determine it ourselves (this may take some time)";
qWarning()
<< "Unreliable duration detected - we will manually determine it ourselves (this may take some time)";
}
// Dump it into the Footage object
int video_streams = 0, audio_streams = 0, still_streams = 0;
for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {
// FFmpeg AVStream
AVStream *avstream = fmt_ctx->streams[i];
// Find decoder for this stream, if it exists we can proceed
const AVCodec* decoder = avcodec_find_decoder(avstream->codecpar->codec_id);
if (decoder
&& (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
|| avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO
|| avstream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
const AVCodec *decoder =
avcodec_find_decoder(avstream->codecpar->codec_id);
if (decoder &&
(avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO ||
avstream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
if (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
AVPixelFormat compatible_pix_fmt = AV_PIX_FMT_NONE;
bool image_is_still = false;
rational pixel_aspect_ratio;
rational frame_rate;
VideoParams::Interlacing interlacing = VideoParams::kInterlaceNone;
VideoParams::Interlacing interlacing =
VideoParams::kInterlaceNone;
{
// Read at least two frames to get more information about this video stream
@@ -357,21 +395,27 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
// Check if video is interlaced and what field dominance it has if so
if (frame->interlaced_frame) {
if (frame->top_field_first) {
interlacing = VideoParams::kInterlacedTopFirst;
interlacing =
VideoParams::kInterlacedTopFirst;
} else {
interlacing = VideoParams::kInterlacedBottomFirst;
interlacing =
VideoParams::kInterlacedBottomFirst;
}
}
pixel_aspect_ratio = av_guess_sample_aspect_ratio(instance.fmt_ctx(),
instance.avstream(),
pixel_aspect_ratio =
av_guess_sample_aspect_ratio(
instance.fmt_ctx(), instance.avstream(),
frame);
frame_rate = av_guess_frame_rate(instance.fmt_ctx(),
instance.avstream(),
frame_rate = av_guess_frame_rate(
instance.fmt_ctx(), instance.avstream(),
frame);
compatible_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(avstream->codecpar->format));
compatible_pix_fmt =
FFmpegUtils::GetCompatiblePixelFormat(
static_cast<AVPixelFormat>(
avstream->codecpar->format));
}
// Read second frame
@@ -379,23 +423,30 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
if (ret >= 0) {
// Check if we need a manual duration
if (avstream->duration == AV_NOPTS_VALUE || duration_guessed_from_bitrate) {
if (footage_duration == AV_NOPTS_VALUE || duration_guessed_from_bitrate) {
if (avstream->duration == AV_NOPTS_VALUE ||
duration_guessed_from_bitrate) {
if (footage_duration == AV_NOPTS_VALUE ||
duration_guessed_from_bitrate) {
// Manually read through file for duration
int64_t new_dur;
do {
new_dur = frame->best_effort_timestamp;
} while (instance.GetFrame(pkt, frame) >= 0 && (!cancelled || !cancelled->IsCancelled()));
new_dur =
frame->best_effort_timestamp;
} while (instance.GetFrame(
pkt, frame) >= 0 &&
(!cancelled ||
!cancelled->IsCancelled()));
avstream->duration = new_dur;
} else {
// Fallback to footage duration
avstream->duration = Timecode::rescale_timestamp_ceil(footage_duration, rational(1, AV_TIME_BASE), avstream->time_base);
avstream->duration =
Timecode::rescale_timestamp_ceil(
footage_duration,
rational(1, AV_TIME_BASE),
avstream->time_base);
}
}
} else if (ret == AVERROR_EOF) {
@@ -414,16 +465,22 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
stream.set_stream_index(i);
stream.set_width(avstream->codecpar->width);
stream.set_height(avstream->codecpar->height);
stream.set_video_type((image_is_still) ? VideoParams::kVideoTypeStill : VideoParams::kVideoTypeVideo);
stream.set_video_type((image_is_still) ?
VideoParams::kVideoTypeStill :
VideoParams::kVideoTypeVideo);
stream.set_format(GetNativePixelFormat(compatible_pix_fmt));
stream.set_channel_count(GetNativeChannelCount(compatible_pix_fmt));
stream.set_channel_count(
GetNativeChannelCount(compatible_pix_fmt));
stream.set_interlacing(interlacing);
stream.set_pixel_aspect_ratio(pixel_aspect_ratio);
stream.set_frame_rate(frame_rate);
stream.set_start_time(avstream->start_time);
stream.set_time_base(avstream->time_base);
stream.set_duration(avstream->duration);
stream.set_color_range(avstream->codecpar->color_range == AVCOL_RANGE_JPEG ? VideoParams::kColorRangeFull : VideoParams::kColorRangeLimited);
stream.set_color_range(avstream->codecpar->color_range ==
AVCOL_RANGE_JPEG ?
VideoParams::kColorRangeFull :
VideoParams::kColorRangeLimited);
// Defaults to false, requires user intervention if incorrect
stream.set_premultiplied_alpha(false);
@@ -436,17 +493,22 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
video_streams++;
}
} else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
} else if (avstream->codecpar->codec_type ==
AVMEDIA_TYPE_AUDIO) {
// Create an audio stream object
AVChannelLayout &channel_layout = avstream->codecpar->ch_layout;
AVChannelLayout &channel_layout =
avstream->codecpar->ch_layout;
if (!av_channel_layout_check(&channel_layout)) {
av_channel_layout_default(&channel_layout,avstream->codecpar->ch_layout.nb_channels);
av_channel_layout_default(
&channel_layout,
avstream->codecpar->ch_layout.nb_channels);
}
if (avstream->duration == AV_NOPTS_VALUE || duration_guessed_from_bitrate) {
if (avstream->duration == AV_NOPTS_VALUE ||
duration_guessed_from_bitrate) {
// Loop through stream until we get the whole duration
if (footage_duration == AV_NOPTS_VALUE || duration_guessed_from_bitrate) {
if (footage_duration == AV_NOPTS_VALUE ||
duration_guessed_from_bitrate) {
Instance instance;
instance.Open(filename_c, avstream->index);
@@ -457,7 +519,8 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
do {
new_dur = frame->best_effort_timestamp;
} while (instance.GetFrame(pkt, frame) >= 0 && (!cancelled || !cancelled->IsCancelled()));
} while (instance.GetFrame(pkt, frame) >= 0 &&
(!cancelled || !cancelled->IsCancelled()));
avstream->duration = new_dur;
@@ -466,9 +529,10 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
instance.Close();
} else {
avstream->duration = Timecode::rescale_timestamp_ceil(footage_duration, rational(1, AV_TIME_BASE), avstream->time_base);
avstream->duration =
Timecode::rescale_timestamp_ceil(
footage_duration, rational(1, AV_TIME_BASE),
avstream->time_base);
}
}
@@ -476,15 +540,17 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
stream.set_stream_index(i);
stream.set_channel_layout(channel_layout);
stream.set_sample_rate(avstream->codecpar->sample_rate);
stream.set_format(FFmpegUtils::GetNativeSampleFormat(static_cast<AVSampleFormat>(avstream->codecpar->format)));
stream.set_format(FFmpegUtils::GetNativeSampleFormat(
static_cast<AVSampleFormat>(
avstream->codecpar->format)));
stream.set_time_base(avstream->time_base);
stream.set_duration(avstream->duration);
desc.AddAudioStream(stream);
audio_streams++;
} else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
} else if (avstream->codecpar->codec_type ==
AVMEDIA_TYPE_SUBTITLE) {
// Limit to SRT for now...
if (avstream->codecpar->codec_id == AV_CODEC_ID_SUBRIP) {
SubtitleParams sub;
@@ -495,10 +561,15 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
instance.Open(filename_c, avstream->index);
while (instance.GetPacket(pkt) >= 0) {
TimeRange time(Timecode::timestamp_to_time(pkt->pts, avstream->time_base),
Timecode::timestamp_to_time(pkt->pts + pkt->duration, avstream->time_base));
TimeRange time(Timecode::timestamp_to_time(
pkt->pts,
avstream->time_base),
Timecode::timestamp_to_time(
pkt->pts + pkt->duration,
avstream->time_base));
QString text = QString::fromUtf8((const char *) pkt->data, pkt->size);
QString text = QString::fromUtf8(
(const char *)pkt->data, pkt->size);
sub.push_back(Subtitle(time, text));
}
@@ -509,11 +580,8 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
desc.AddSubtitleStream(sub);
}
}
}
}
desc.SetStreamCount(fmt_ctx->nb_streams);
@@ -527,7 +595,6 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
vp.set_enabled(false);
}
}
}
// Free all memory
@@ -543,7 +610,9 @@ QString FFmpegDecoder::FFmpegError(int error_code)
return QStringLiteral("%1 %2").arg(QString::number(error_code), err);
}
bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, const AudioParams &params, CancelAtom *cancelled)
bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames,
const AudioParams &params,
CancelAtom *cancelled)
{
// Iterate through each audio frame and extract the PCM data
@@ -551,23 +620,22 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
instance_.Seek(0);
// Handle NULL channel layout
AVChannelLayout channel_layout = ValidateChannelLayout(instance_.avstream());
AVChannelLayout channel_layout =
ValidateChannelLayout(instance_.avstream());
if (!av_channel_layout_check(&channel_layout)) {
qCritical() << "Failed to determine channel layout of audio file, could not conform";
qCritical()
<< "Failed to determine channel layout of audio file, could not conform";
return false;
}
// Create resampling context
AVChannelLayout layout = params.channel_layout();
SwrContext *resampler;
swr_alloc_set_opts2(&resampler,
&layout,
swr_alloc_set_opts2(
&resampler, &layout,
FFmpegUtils::GetFFmpegSampleFormat(params.format()),
params.sample_rate(),
&channel_layout,
params.sample_rate(), &channel_layout,
static_cast<AVSampleFormat>(instance_.avstream()->codecpar->format),
instance_.avstream()->codecpar->sample_rate,
0,
nullptr);
instance_.avstream()->codecpar->sample_rate, 0, nullptr);
av_channel_layout_uninit(&layout);
swr_init(resampler);
@@ -582,7 +650,9 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
duration = instance_.fmt_ctx()->duration;
if (!(duration == 0 || duration == AV_NOPTS_VALUE)) {
// Rescale from AVFormatContext timebase to AVStream timebase
duration = av_rescale_q_rnd(duration, {1, AV_TIME_BASE}, instance_.avstream()->time_base, AV_ROUND_UP);
duration = av_rescale_q_rnd(duration, { 1, AV_TIME_BASE },
instance_.avstream()->time_base,
AV_ROUND_UP);
}
}
@@ -601,7 +671,6 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
ret = instance_.GetFrame(pkt, frame);
if (ret < 0) {
if (ret == AVERROR_EOF) {
success = true;
} else {
@@ -610,29 +679,33 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
qWarning() << "Failed to conform:" << ret << err_str;
}
break;
}
// Allocate buffers
int nb_samples = swr_get_out_samples(resampler, frame->nb_samples);
int nb_bytes_per_channel = params.samples_to_bytes(nb_samples) / nb_channels;
int nb_bytes_per_channel =
params.samples_to_bytes(nb_samples) / nb_channels;
data.set_sample_count(nb_bytes_per_channel);
data.allocate();
// Resample audio to our destination parameters
nb_samples = swr_convert(resampler,
nb_samples = swr_convert(
resampler,
reinterpret_cast<uint8_t **>(data.to_raw_ptrs().data()),
nb_samples,
const_cast<const uint8_t**>(frame->data),
nb_samples, const_cast<const uint8_t **>(frame->data),
frame->nb_samples);
// If no error, write to files
if (nb_samples > 0) {
// Update byte count for the number of samples we actually received
nb_bytes_per_channel = params.samples_to_bytes(nb_samples) / nb_channels;
nb_bytes_per_channel =
params.samples_to_bytes(nb_samples) / nb_channels;
// Write to files
wave_out.write(const_cast<const char**>(reinterpret_cast<char**>(data.to_raw_ptrs().data())), nb_bytes_per_channel);
wave_out.write(
const_cast<const char **>(
reinterpret_cast<char **>(data.to_raw_ptrs().data())),
nb_bytes_per_channel);
}
// Free buffer
@@ -642,7 +715,8 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
if (nb_samples < 0) {
char err_str[512];
av_strerror(nb_samples, err_str, 512);
qWarning() << "libswresample failed with error:" << nb_samples << err_str;
qWarning() << "libswresample failed with error:" << nb_samples
<< err_str;
break;
}
@@ -700,7 +774,8 @@ AVChannelLayout FFmpegDecoder::ValidateChannelLayout(AVStream* stream)
return layout;
}
const char *FFmpegDecoder::GetInterlacingModeInFFmpeg(VideoParams::Interlacing interlacing)
const char *
FFmpegDecoder::GetInterlacingModeInFFmpeg(VideoParams::Interlacing interlacing)
{
if (interlacing == VideoParams::kInterlacedTopFirst) {
return "tff";
@@ -740,13 +815,15 @@ void FFmpegDecoder::ClearFrameCache()
}
}
AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f, const RetrieveVideoParams &p)
AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f,
const RetrieveVideoParams &p)
{
// In pre-processing, we try to achieve the following:
// - If a divider is being used, scale down the image
// - If a pixel format is not compatible with the GLSL shader, convert it to RGBA ourselves
if (p.divider == 1 && IsPixelFormatGLSLCompatible(static_cast<AVPixelFormat>(f->format))) {
if (p.divider == 1 &&
IsPixelFormatGLSLCompatible(static_cast<AVPixelFormat>(f->format))) {
// No CPU processing required, the user wants this in full resolution and the pixel format can
// be converted on the GPU
return f;
@@ -766,8 +843,10 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f, const RetrieveVideoParam
dest->height = VideoParams::GetScaledDimension(dest->height, p.divider);
}
if (!IsPixelFormatGLSLCompatible(static_cast<AVPixelFormat>(dest->format))) {
dest->format = FFmpegUtils::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(dest->format), p.maximum_format);
if (!IsPixelFormatGLSLCompatible(
static_cast<AVPixelFormat>(dest->format))) {
dest->format = FFmpegUtils::GetCompatiblePixelFormat(
static_cast<AVPixelFormat>(dest->format), p.maximum_format);
}
int r = av_frame_get_buffer(dest.get(), 0);
@@ -776,15 +855,11 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f, const RetrieveVideoParam
return nullptr;
}
if (!sws_ctx_
|| sws_src_width_ != f->width
|| sws_src_height_ != f->height
|| sws_src_format_ != f->format
|| sws_dst_width_ != dest->width
|| sws_dst_height_ != dest->height
|| sws_dst_format_ != dest->format
|| sws_colrange_ != dest->color_range
|| sws_colspace_ != dest->colorspace) {
if (!sws_ctx_ || sws_src_width_ != f->width ||
sws_src_height_ != f->height || sws_src_format_ != f->format ||
sws_dst_width_ != dest->width || sws_dst_height_ != dest->height ||
sws_dst_format_ != dest->format || sws_colrange_ != dest->color_range ||
sws_colspace_ != dest->colorspace) {
// SwsContext must be recreated, destroy current if it exists
FreeScaler();
@@ -799,27 +874,24 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f, const RetrieveVideoParam
sws_colspace_ = dest->colorspace;
// Create new scaler
sws_ctx_ = sws_getContext(sws_src_width_,
sws_src_height_,
sws_src_format_,
sws_dst_width_,
sws_dst_height_,
sws_dst_format_,
SWS_POINT,
nullptr,
nullptr,
nullptr);
sws_ctx_ = sws_getContext(sws_src_width_, sws_src_height_,
sws_src_format_, sws_dst_width_,
sws_dst_height_, sws_dst_format_, SWS_POINT,
nullptr, nullptr, nullptr);
// Set swscale's colorspace details
sws_setColorspaceDetails(sws_ctx_,
sws_getCoefficients(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(dest->colorspace)),
sws_setColorspaceDetails(
sws_ctx_,
sws_getCoefficients(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(
dest->colorspace)),
dest->color_range == AVCOL_RANGE_JPEG ? 1 : 0,
sws_getCoefficients(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(dest->colorspace)),
dest->color_range == AVCOL_RANGE_JPEG ? 1 : 0,
0, 0x10000, 0x10000);
sws_getCoefficients(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(
dest->colorspace)),
dest->color_range == AVCOL_RANGE_JPEG ? 1 : 0, 0, 0x10000, 0x10000);
}
r = sws_scale(sws_ctx_, f->data, f->linesize, 0, f->height, dest->data, dest->linesize);
r = sws_scale(sws_ctx_, f->data, f->linesize, 0, f->height, dest->data,
dest->linesize);
if (r < 0) {
FFmpegError(r);
return nullptr;
@@ -828,12 +900,16 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f, const RetrieveVideoParam
return dest;
}
AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, CancelAtom *cancelled)
AVFramePtr FFmpegDecoder::RetrieveFrame(const rational &time,
CancelAtom *cancelled)
{
int64_t target_ts = Timecode::time_to_timestamp(time, instance_.avstream()->time_base);
int64_t target_ts =
Timecode::time_to_timestamp(time, instance_.avstream()->time_base);
if (instance_.fmt_ctx()->start_time != AV_NOPTS_VALUE) {
target_ts += av_rescale_q(instance_.fmt_ctx()->start_time, {1, AV_TIME_BASE}, instance_.avstream()->time_base);
target_ts += av_rescale_q(instance_.fmt_ctx()->start_time,
{ 1, AV_TIME_BASE },
instance_.avstream()->time_base);
}
const int64_t min_seek = 0;
@@ -842,8 +918,9 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, CancelAtom *cancel
if (time != kAnyTimecode) {
// If the frame wasn't in the frame cache, see if this frame cache is too old to use
if (cached_frames_.empty()
|| (target_ts < cached_frames_.front()->pts || target_ts > cached_frames_.back()->pts + 2*second_ts_)) {
if (cached_frames_.empty() ||
(target_ts < cached_frames_.front()->pts ||
target_ts > cached_frames_.back()->pts + 2 * second_ts_)) {
ClearFrameCache();
instance_.Seek(seek_ts);
@@ -891,8 +968,9 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, CancelAtom *cancel
if (still_seeking) {
// Handle a failure to seek (occurs on some media)
// We'll only be here if the frame cache was emptied earlier
if (!cache_at_zero_ && (ret == AVERROR_EOF || filtered->best_effort_timestamp > target_ts)) {
if (!cache_at_zero_ &&
(ret == AVERROR_EOF ||
filtered->best_effort_timestamp > target_ts)) {
seek_ts = qMax(min_seek, seek_ts - second_ts_);
instance_.Seek(seek_ts);
if (seek_ts == min_seek) {
@@ -901,19 +979,17 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, CancelAtom *cancel
continue;
} else {
still_seeking = false;
}
}
if (ret == AVERROR_EOF) {
// Handle an "expected" EOF by using the last frame of our cache
cache_at_eof_ = true;
if (cached_frames_.empty()) {
qCritical() << "Unexpected codec EOF - unable to retrieve frame";
qCritical()
<< "Unexpected codec EOF - unable to retrieve frame";
} else {
return_frame = cached_frames_.back();
}
@@ -921,7 +997,6 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, CancelAtom *cancel
break;
} else {
// Cut down to thread count - 1 before we acquire a new frame
if (cached_frames_.size() > size_t(MaximumQueueSize())) {
RemoveFirstFrame();
@@ -972,31 +1047,30 @@ void FFmpegDecoder::FreeScaler()
AVFramePtr FFmpegDecoder::GetFrameFromCache(const int64_t &t) const
{
if (t < cached_frames_.front()->pts) {
if (cache_at_zero_) {
return cached_frames_.front();
}
} else if (t > cached_frames_.back()->pts) {
if (cache_at_eof_) {
return cached_frames_.back();
}
} else {
// We already have this frame in the cache, find it
for (auto it=cached_frames_.cbegin(); it!=cached_frames_.cend(); it++) {
for (auto it = cached_frames_.cbegin(); it != cached_frames_.cend();
it++) {
AVFramePtr this_frame = *it;
auto next = it;
next++;
if (this_frame->pts == t // Test for an exact match
|| (next != cached_frames_.cend() && (*next)->pts > t)) { // Or for this frame to be the "closest"
||
(next != cached_frames_.cend() &&
(*next)->pts > t)) { // Or for this frame to be the "closest"
return this_frame;
}
}
}
@@ -1019,11 +1093,11 @@ int FFmpegDecoder::MaximumQueueSize()
return 2;
}
FFmpegDecoder::Instance::Instance() :
fmt_ctx_(nullptr),
codec_ctx_(nullptr),
avstream_(nullptr),
opts_(nullptr)
FFmpegDecoder::Instance::Instance()
: fmt_ctx_(nullptr)
, codec_ctx_(nullptr)
, avstream_(nullptr)
, opts_(nullptr)
{
}
@@ -1034,7 +1108,8 @@ bool FFmpegDecoder::Instance::Open(const char *filename, int stream_index)
// Handle format context error
if (error_code != 0) {
qCritical() << "Failed to open input:" << filename << FFmpegError(error_code);
qCritical()
<< "Failed to open input:" << filename << FFmpegError(error_code);
return false;
}
@@ -1055,10 +1130,9 @@ bool FFmpegDecoder::Instance::Open(const char *filename, int stream_index)
// Handle failure to find decoder
if (codec == nullptr) {
qCritical() << "Failed to find appropriate decoder for this codec:"
<< filename
<< stream_index
<< avstream_->codecpar->codec_id;
qCritical()
<< "Failed to find appropriate decoder for this codec:" << filename
<< stream_index << avstream_->codecpar->codec_id;
return false;
}
@@ -1074,7 +1148,8 @@ bool FFmpegDecoder::Instance::Open(const char *filename, int stream_index)
// Handle failure to copy parameters
if (error_code < 0) {
qCritical() << "Failed to copy parameters from AVStream to AVCodecContext";
qCritical()
<< "Failed to copy parameters from AVStream to AVCodecContext";
return false;
}
@@ -1125,8 +1200,9 @@ int FFmpegDecoder::Instance::GetFrame(AVPacket *pkt, AVFrame *frame)
// Clear any previous frames
av_frame_unref(frame);
while ((ret = avcodec_receive_frame(codec_ctx_, frame)) == AVERROR(EAGAIN) && !eof) {
while ((ret = avcodec_receive_frame(codec_ctx_, frame)) ==
AVERROR(EAGAIN) &&
!eof) {
// Find next packet in the correct stream index
ret = GetPacket(pkt);
+24 -14
View File
@@ -39,13 +39,13 @@ extern "C" {
#include "codec/decoder.h"
#include "common/ffmpegutils.h"
namespace olive {
namespace olive
{
/**
* @brief A Decoder derivative that wraps FFmpeg functions as on Olive decoder
*/
class FFmpegDecoder : public Decoder
{
class FFmpegDecoder : public Decoder {
Q_OBJECT
public:
// Constructor
@@ -56,22 +56,31 @@ public:
virtual QString id() const override;
virtual bool SupportsVideo() override{return true;}
virtual bool SupportsAudio() override{return true;}
virtual bool SupportsVideo() override
{
return true;
}
virtual bool SupportsAudio() override
{
return true;
}
virtual FootageDescription Probe(const QString &filename, CancelAtom *cancelled) const override;
virtual FootageDescription Probe(const QString &filename,
CancelAtom *cancelled) const override;
protected:
virtual bool OpenInternal() override;
virtual TexturePtr RetrieveVideoInternal(const RetrieveVideoParams& p) override;
virtual bool ConformAudioInternal(const QVector<QString>& filenames, const AudioParams &params, CancelAtom *cancelled) override;
virtual TexturePtr
RetrieveVideoInternal(const RetrieveVideoParams &p) override;
virtual bool ConformAudioInternal(const QVector<QString> &filenames,
const AudioParams &params,
CancelAtom *cancelled) override;
virtual void CloseInternal() override;
virtual rational GetAudioStartOffset() const override;
private:
class Instance
{
class Instance {
public:
Instance();
@@ -121,7 +130,6 @@ private:
AVCodecContext *codec_ctx_;
AVStream *avstream_;
AVDictionary *opts_;
};
/**
@@ -141,7 +149,8 @@ private:
static AVChannelLayout ValidateChannelLayout(AVStream *stream);
static const char* GetInterlacingModeInFFmpeg(VideoParams::Interlacing interlacing);
static const char *
GetInterlacingModeInFFmpeg(VideoParams::Interlacing interlacing);
static bool IsPixelFormatGLSLCompatible(AVPixelFormat f);
@@ -151,7 +160,9 @@ private:
AVFramePtr PreProcessFrame(AVFramePtr f, const RetrieveVideoParams &p);
TexturePtr ProcessFrameIntoTexture(AVFramePtr f, const RetrieveVideoParams &p, const AVFramePtr original);
TexturePtr ProcessFrameIntoTexture(AVFramePtr f,
const RetrieveVideoParams &p,
const AVFramePtr original);
AVFramePtr RetrieveFrame(const rational &time, CancelAtom *cancelled);
@@ -179,7 +190,6 @@ private:
bool cache_at_eof_;
Instance instance_;
};
}
+192 -112
View File
@@ -30,21 +30,22 @@ extern "C" {
#include "common/ffmpegutils.h"
namespace olive {
namespace olive
{
FFmpegEncoder::FFmpegEncoder(const EncodingParams &params) :
Encoder(params),
fmt_ctx_(nullptr),
video_stream_(nullptr),
video_codec_ctx_(nullptr),
video_scale_ctx_(nullptr),
video_buffersrc_ctx_(nullptr),
video_buffersink_ctx_(nullptr),
audio_stream_(nullptr),
audio_codec_ctx_(nullptr),
audio_resample_ctx_(nullptr),
audio_frame_(nullptr),
open_(false)
FFmpegEncoder::FFmpegEncoder(const EncodingParams &params)
: Encoder(params)
, fmt_ctx_(nullptr)
, video_stream_(nullptr)
, video_codec_ctx_(nullptr)
, video_scale_ctx_(nullptr)
, video_buffersrc_ctx_(nullptr)
, video_buffersink_ctx_(nullptr)
, audio_stream_(nullptr)
, audio_codec_ctx_(nullptr)
, audio_resample_ctx_(nullptr)
, audio_frame_(nullptr)
, open_(false)
{
}
@@ -56,12 +57,14 @@ QStringList FFmpegEncoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const
if (codec_info) {
for (int i = 0; codec_info->pix_fmts[i] != -1; i++) {
if (FFmpegUtils::ConvertJPEGSpaceToRegularSpace(codec_info->pix_fmts[i]) != codec_info->pix_fmts[i]) {
if (FFmpegUtils::ConvertJPEGSpaceToRegularSpace(
codec_info->pix_fmts[i]) != codec_info->pix_fmts[i]) {
// This is a deprecated "JPEG" space, skip it
continue;
}
const char* pix_fmt_name = av_get_pix_fmt_name(codec_info->pix_fmts[i]);
const char *pix_fmt_name =
av_get_pix_fmt_name(codec_info->pix_fmts[i]);
pix_fmts.append(pix_fmt_name);
}
}
@@ -69,7 +72,8 @@ QStringList FFmpegEncoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const
return pix_fmts;
}
std::vector<SampleFormat> FFmpegEncoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
std::vector<SampleFormat>
FFmpegEncoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
{
std::vector<SampleFormat> f;
@@ -77,20 +81,15 @@ std::vector<SampleFormat> FFmpegEncoder::GetSampleFormatsForCodec(ExportCodec::C
// FFmpeg lists these as separate codecs so we need custom functionality here
// We list signed 16 first because ExportDialog will always use the first element by default
// (because first element is the "default" in tFFmpeg)
f = {
SampleFormat::S16,
SampleFormat::U8,
SampleFormat::S32,
SampleFormat::S64,
SampleFormat::F32,
SampleFormat::F64
};
f = { SampleFormat::S16, SampleFormat::U8, SampleFormat::S32,
SampleFormat::S64, SampleFormat::F32, SampleFormat::F64 };
} else {
const AVCodec *codec_info = GetEncoder(c, SampleFormat::INVALID);
if (codec_info && codec_info->sample_fmts) {
for (int i = 0; codec_info->sample_fmts[i] != -1; i++) {
SampleFormat this_format = FFmpegUtils::GetNativeSampleFormat(static_cast<AVSampleFormat>(codec_info->sample_fmts[i]));
SampleFormat this_format = FFmpegUtils::GetNativeSampleFormat(
static_cast<AVSampleFormat>(codec_info->sample_fmts[i]));
if (this_format != SampleFormat::INVALID) {
f.push_back(this_format);
}
@@ -114,7 +113,8 @@ bool FFmpegEncoder::Open()
const char *filename_c_str = filename_bytes.constData();
// Create output format context
error_code = avformat_alloc_output_context2(&fmt_ctx_, nullptr, nullptr, filename_c_str);
error_code = avformat_alloc_output_context2(&fmt_ctx_, nullptr, nullptr,
filename_c_str);
// Check error code
if (error_code < 0) {
@@ -124,7 +124,8 @@ bool FFmpegEncoder::Open()
// Initialize a video stream if it's enabled
if (params().video_enabled()) {
if (!InitializeStream(AVMEDIA_TYPE_VIDEO, &video_stream_, &video_codec_ctx_, params().video_codec())) {
if (!InitializeStream(AVMEDIA_TYPE_VIDEO, &video_stream_,
&video_codec_ctx_, params().video_codec())) {
return false;
}
@@ -132,17 +133,20 @@ bool FFmpegEncoder::Open()
PixelFormat native_pixel_fmt = params().video_params().format();
// This is the format we will need to convert the frame to for swscale to understand it
video_conversion_fmt_ = FFmpegUtils::GetCompatiblePixelFormat(native_pixel_fmt);
video_conversion_fmt_ =
FFmpegUtils::GetCompatiblePixelFormat(native_pixel_fmt);
// This is the equivalent pixel format above as an AVPixelFormat that swscale can understand
AVPixelFormat src_alpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(video_conversion_fmt_,
VideoParams::kRGBAChannelCount);
AVPixelFormat src_alpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(
video_conversion_fmt_, VideoParams::kRGBAChannelCount);
AVPixelFormat src_noalpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(video_conversion_fmt_,
VideoParams::kRGBChannelCount);
AVPixelFormat src_noalpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(
video_conversion_fmt_, VideoParams::kRGBChannelCount);
if (src_alpha_pix_fmt == AV_PIX_FMT_NONE || src_noalpha_pix_fmt == AV_PIX_FMT_NONE) {
SetError(tr("Failed to find suitable pixel format for this buffer"));
if (src_alpha_pix_fmt == AV_PIX_FMT_NONE ||
src_noalpha_pix_fmt == AV_PIX_FMT_NONE) {
SetError(
tr("Failed to find suitable pixel format for this buffer"));
return false;
}
@@ -157,17 +161,22 @@ bool FFmpegEncoder::Open()
static const int FILTER_ARG_SZ = 1024;
char filter_args[FILTER_ARG_SZ];
snprintf(filter_args, FILTER_ARG_SZ, "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
snprintf(
filter_args, FILTER_ARG_SZ,
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
params().video_params().effective_width(),
params().video_params().effective_height(),
src_alpha_pix_fmt,
params().video_params().effective_height(), src_alpha_pix_fmt,
params().video_params().time_base().numerator(),
params().video_params().time_base().denominator(),
params().video_params().pixel_aspect_ratio().numerator(),
params().video_params().pixel_aspect_ratio().denominator());
avfilter_graph_create_filter(&video_buffersrc_ctx_, avfilter_get_by_name("buffer"), "in", filter_args, nullptr, video_scale_ctx_);
avfilter_graph_create_filter(&video_buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", nullptr, nullptr, video_scale_ctx_);
avfilter_graph_create_filter(&video_buffersrc_ctx_,
avfilter_get_by_name("buffer"), "in",
filter_args, nullptr, video_scale_ctx_);
avfilter_graph_create_filter(&video_buffersink_ctx_,
avfilter_get_by_name("buffersink"), "out",
nullptr, nullptr, video_scale_ctx_);
AVFilterContext *last_filter = video_buffersrc_ctx_;
@@ -176,9 +185,15 @@ bool FFmpegEncoder::Open()
AVFilterContext *range_filter;
snprintf(filter_args, FILTER_ARG_SZ, "in_range=full:out_range=%s",
params().video_params().color_range() == VideoParams::kColorRangeFull ? "full" : "limited");
params().video_params().color_range() ==
VideoParams::kColorRangeFull ?
"full" :
"limited");
avfilter_graph_create_filter(&range_filter, avfilter_get_by_name("scale"), "range", filter_args, nullptr, video_scale_ctx_);
avfilter_graph_create_filter(&range_filter,
avfilter_get_by_name("scale"), "range",
filter_args, nullptr,
video_scale_ctx_);
avfilter_link(last_filter, 0, range_filter, 0);
last_filter = range_filter;
@@ -188,9 +203,13 @@ bool FFmpegEncoder::Open()
// Transform pixel format
AVFilterContext *format_filter;
snprintf(filter_args, FILTER_ARG_SZ, "pix_fmts=%u", encoder_pix_fmt);
snprintf(filter_args, FILTER_ARG_SZ, "pix_fmts=%u",
encoder_pix_fmt);
avfilter_graph_create_filter(&format_filter, avfilter_get_by_name("format"), "format", filter_args, nullptr, video_scale_ctx_);
avfilter_graph_create_filter(&format_filter,
avfilter_get_by_name("format"),
"format", filter_args, nullptr,
video_scale_ctx_);
avfilter_link(last_filter, 0, format_filter, 0);
last_filter = format_filter;
@@ -206,14 +225,17 @@ bool FFmpegEncoder::Open()
// Initialize an audio stream if it's enabled
if (params().audio_enabled()) {
if (!InitializeStream(AVMEDIA_TYPE_AUDIO, &audio_stream_, &audio_codec_ctx_, params().audio_codec())) {
if (!InitializeStream(AVMEDIA_TYPE_AUDIO, &audio_stream_,
&audio_codec_ctx_, params().audio_codec())) {
return false;
}
}
// Initialize a subtitle stream if it's enabled
if (params().subtitles_enabled()) {
if (!InitializeStream(AVMEDIA_TYPE_SUBTITLE, &subtitle_stream_, &subtitle_codec_ctx_, params().subtitles_codec())) {
if (!InitializeStream(AVMEDIA_TYPE_SUBTITLE, &subtitle_stream_,
&subtitle_codec_ctx_,
params().subtitles_codec())) {
return false;
}
}
@@ -249,7 +271,8 @@ bool FFmpegEncoder::WriteFrame(FramePtr frame, rational time)
AVFramePtr input_frame = CreateAVFramePtr(av_frame_alloc());
input_frame->width = frame->width();
input_frame->height = frame->height();
input_frame->format = FFmpegUtils::GetFFmpegPixelFormat(frame->format(), frame->channel_count());
input_frame->format = FFmpegUtils::GetFFmpegPixelFormat(
frame->format(), frame->channel_count());
input_frame->data[0] = reinterpret_cast<uint8_t *>(frame->data());
input_frame->linesize[0] = frame->linesize_bytes();
@@ -259,7 +282,8 @@ bool FFmpegEncoder::WriteFrame(FramePtr frame, rational time)
input_frame->color_range = video_codec_ctx_->color_range;
int r;
r = av_buffersrc_add_frame_flags(video_buffersrc_ctx_, input_frame.get(), AV_BUFFERSRC_FLAG_KEEP_REF);
r = av_buffersrc_add_frame_flags(video_buffersrc_ctx_, input_frame.get(),
AV_BUFFERSRC_FLAG_KEEP_REF);
if (r < 0) {
FFmpegError(tr("Failed to add frame to filter graph"), r);
return false;
@@ -272,7 +296,8 @@ bool FFmpegEncoder::WriteFrame(FramePtr frame, rational time)
return false;
}
encoded_frame->pts = qRound64(time.toDouble() / av_q2d(video_codec_ctx_->time_base));
encoded_frame->pts =
qRound64(time.toDouble() / av_q2d(video_codec_ctx_->time_base));
return WriteAVFrame(encoded_frame.get(), video_codec_ctx_, video_stream_);
}
@@ -295,8 +320,11 @@ bool FFmpegEncoder::WriteAudio(const SampleBuffer &audio)
size_t input_sample_count = std::min(end - start, max_frame);
int input_linesize;
int r = av_samples_alloc_array_and_samples(&input_data, &input_linesize, audio.audio_params().channel_count(),
input_sample_count, FFmpegUtils::GetFFmpegSampleFormat(audio.audio_params().format()), 0);
int r = av_samples_alloc_array_and_samples(
&input_data, &input_linesize, audio.audio_params().channel_count(),
input_sample_count,
FFmpegUtils::GetFFmpegSampleFormat(audio.audio_params().format()),
0);
if (r < 0) {
FFmpegError(tr("Failed to allocate sample array"), r);
@@ -304,13 +332,18 @@ bool FFmpegEncoder::WriteAudio(const SampleBuffer &audio)
} else {
int bpsc = audio.audio_params().bytes_per_sample_per_channel();
for (int i = 0; i < audio.audio_params().channel_count(); i++) {
memcpy(input_data[i], audio.data(i) + start, input_sample_count * bpsc);
memcpy(input_data[i], audio.data(i) + start,
input_sample_count * bpsc);
}
start += input_sample_count;
}
result = WriteAudioData(audio.audio_params().is_valid() ? audio.audio_params() : params().audio_params(), const_cast<const uint8_t**>(input_data), input_sample_count);
result = WriteAudioData(audio.audio_params().is_valid() ?
audio.audio_params() :
params().audio_params(),
const_cast<const uint8_t **>(input_data),
input_sample_count);
if (input_data) {
av_freep(&input_data[0]);
@@ -321,7 +354,9 @@ bool FFmpegEncoder::WriteAudio(const SampleBuffer &audio)
return result;
}
bool FFmpegEncoder::WriteAudioData(const AudioParams &audio_params, const uint8_t **input_data, int input_sample_count)
bool FFmpegEncoder::WriteAudioData(const AudioParams &audio_params,
const uint8_t **input_data,
int input_sample_count)
{
if (!InitializeResampleContext(audio_params)) {
qCritical() << "Failed to initialize resample context";
@@ -331,32 +366,46 @@ bool FFmpegEncoder::WriteAudioData(const AudioParams &audio_params, const uint8_
bool result = true;
// Create output buffer
int output_sample_count = input_sample_count ? swr_get_out_samples(audio_resample_ctx_, input_sample_count) : 102400;
int output_sample_count =
input_sample_count ?
swr_get_out_samples(audio_resample_ctx_, input_sample_count) :
102400;
uint8_t **output_data = nullptr;
int output_linesize;
av_samples_alloc_array_and_samples(&output_data, &output_linesize, audio_stream_->codecpar->ch_layout.nb_channels,
output_sample_count, static_cast<AVSampleFormat>(audio_stream_->codecpar->format), 0);
av_samples_alloc_array_and_samples(
&output_data, &output_linesize,
audio_stream_->codecpar->ch_layout.nb_channels, output_sample_count,
static_cast<AVSampleFormat>(audio_stream_->codecpar->format), 0);
// Perform conversion
int converted = swr_convert(audio_resample_ctx_, output_data, output_sample_count, const_cast<const uint8_t**>(input_data), input_sample_count);
int converted = swr_convert(audio_resample_ctx_, output_data,
output_sample_count,
const_cast<const uint8_t **>(input_data),
input_sample_count);
if (converted > 0) {
// Split sample buffer into frames
for (int i = 0; i < converted;) {
int frame_remaining_samples = audio_max_samples_ - audio_frame_offset_;
int frame_remaining_samples =
audio_max_samples_ - audio_frame_offset_;
int converted_remaining_samples = converted - i;
int copy_length = qMin(frame_remaining_samples, converted_remaining_samples);
int copy_length =
qMin(frame_remaining_samples, converted_remaining_samples);
av_samples_copy(audio_frame_->data, output_data, audio_frame_offset_, i,
copy_length,
audio_frame_->ch_layout.nb_channels, static_cast<AVSampleFormat>(audio_frame_->format));
av_samples_copy(audio_frame_->data, output_data,
audio_frame_offset_, i, copy_length,
audio_frame_->ch_layout.nb_channels,
static_cast<AVSampleFormat>(audio_frame_->format));
audio_frame_offset_ += copy_length;
i += copy_length;
if (audio_frame_offset_ == audio_max_samples_ || (i == converted && !input_data)) {
if (audio_frame_offset_ == audio_max_samples_ ||
(i == converted && !input_data)) {
// Got all the samples we needed, write the frame
audio_frame_->pts = av_rescale_q(audio_write_count_, {1, audio_codec_ctx_->sample_rate}, audio_codec_ctx_->time_base);
audio_frame_->pts = av_rescale_q(
audio_write_count_, { 1, audio_codec_ctx_->sample_rate },
audio_codec_ctx_->time_base);
WriteAVFrame(audio_frame_, audio_codec_ctx_, audio_stream_);
audio_write_count_ += audio_frame_offset_;
@@ -370,7 +419,9 @@ bool FFmpegEncoder::WriteAudioData(const AudioParams &audio_params, const uint8_
if (!input_data && audio_frame_offset_ > 0) {
audio_frame_->nb_samples = audio_frame_offset_;
audio_frame_->pts = av_rescale_q(audio_write_count_, {1, audio_codec_ctx_->sample_rate}, audio_codec_ctx_->time_base);
audio_frame_->pts = av_rescale_q(audio_write_count_,
{ 1, audio_codec_ctx_->sample_rate },
audio_codec_ctx_->time_base);
WriteAVFrame(audio_frame_, audio_codec_ctx_, audio_stream_);
}
@@ -392,12 +443,11 @@ QString GetAssTime(const rational &time)
int64_t mm = (total_centiseconds / 6000) % 60;
int64_t hh = total_centiseconds / 360000;
return QStringLiteral("%1:%2:%3.%4").arg(
QString::number(hh),
return QStringLiteral("%1:%2:%3.%4")
.arg(QString::number(hh),
QStringLiteral("%1").arg(mm, 2, 10, QLatin1Char('0')),
QStringLiteral("%1").arg(ss, 2, 10, QLatin1Char('0')),
QStringLiteral("%1").arg(cs, 2, 10, QLatin1Char('0'))
);
QStringLiteral("%1").arg(cs, 2, 10, QLatin1Char('0')));
}
bool FFmpegEncoder::WriteSubtitle(const SubtitleBlock *sub_block)
@@ -409,10 +459,14 @@ bool FFmpegEncoder::WriteSubtitle(const SubtitleBlock *sub_block)
pkt->stream_index = subtitle_stream_->index;
pkt->data = (uint8_t *)utf8_sub.data();
pkt->size = utf8_sub.size();
pkt->pts = Timecode::time_to_timestamp(sub_block->in(), subtitle_codec_ctx_->time_base, Timecode::kFloor);
pkt->duration = av_rescale_q(qRound64(sub_block->length().toDouble() * 1000), {1, 1000}, subtitle_codec_ctx_->time_base);
pkt->pts = Timecode::time_to_timestamp(
sub_block->in(), subtitle_codec_ctx_->time_base, Timecode::kFloor);
pkt->duration =
av_rescale_q(qRound64(sub_block->length().toDouble() * 1000),
{ 1, 1000 }, subtitle_codec_ctx_->time_base);
pkt->dts = pkt->pts;
av_packet_rescale_ts(pkt, subtitle_codec_ctx_->time_base, subtitle_stream_->time_base);
av_packet_rescale_ts(pkt, subtitle_codec_ctx_->time_base,
subtitle_stream_->time_base);
int err = av_interleaved_write_frame(fmt_ctx_, pkt);
bool ret = true;
@@ -541,12 +595,14 @@ void FFmpegEncoder::FFmpegError(const QString& context, int error_code)
char err[1024];
av_strerror(error_code, err, 1024);
QString formatted_err = tr("%1: %2 %3").arg(context, err, QString::number(error_code));
QString formatted_err =
tr("%1: %2 %3").arg(context, err, QString::number(error_code));
qDebug() << formatted_err;
SetError(formatted_err);
}
bool FFmpegEncoder::WriteAVFrame(AVFrame *frame, AVCodecContext* codec_ctx, AVStream* stream)
bool FFmpegEncoder::WriteAVFrame(AVFrame *frame, AVCodecContext *codec_ctx,
AVStream *stream)
{
// Send raw frame to the encoder
int error_code = avcodec_send_frame(codec_ctx, frame);
@@ -567,7 +623,8 @@ bool FFmpegEncoder::WriteAVFrame(AVFrame *frame, AVCodecContext* codec_ctx, AVSt
if (error_code == AVERROR(EAGAIN)) {
break;
} else if (error_code < 0) {
FFmpegError(tr("Failed to receive packet from decoder"), error_code);
FFmpegError(tr("Failed to receive packet from decoder"),
error_code);
goto fail;
}
@@ -595,22 +652,29 @@ fail:
return succeeded;
}
bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AVCodecContext** codec_ctx_ptr, const ExportCodec::Codec& codec)
bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream **stream_ptr,
AVCodecContext **codec_ctx_ptr,
const ExportCodec::Codec &codec)
{
if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO && type != AVMEDIA_TYPE_SUBTITLE) {
SetError(tr("Cannot initialize a stream that is not a video, audio, or subtitle type"));
if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO &&
type != AVMEDIA_TYPE_SUBTITLE) {
SetError(tr(
"Cannot initialize a stream that is not a video, audio, or subtitle type"));
return false;
}
// Find encoder
const AVCodec* encoder = GetEncoder(codec, params().audio_params().format());
const AVCodec *encoder =
GetEncoder(codec, params().audio_params().format());
if (!encoder) {
SetError(tr("Failed to find codec for 0x%1").arg(codec, 16));
return false;
}
if (encoder->type != type) {
SetError(tr("Retrieved unexpected codec type %1 for codec %2").arg(QString::number(encoder->type), QString::number(codec)));
SetError(
tr("Retrieved unexpected codec type %1 for codec %2")
.arg(QString::number(encoder->type), QString::number(codec)));
return false;
}
@@ -625,35 +689,47 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV
if (type == AVMEDIA_TYPE_VIDEO) {
codec_ctx->width = params().video_params().width();
codec_ctx->height = params().video_params().height();
codec_ctx->sample_aspect_ratio = params().video_params().pixel_aspect_ratio().toAVRational();
codec_ctx->time_base = params().video_params().frame_rate_as_time_base().toAVRational();
codec_ctx->framerate = params().video_params().frame_rate().toAVRational();
codec_ctx->sample_aspect_ratio =
params().video_params().pixel_aspect_ratio().toAVRational();
codec_ctx->time_base =
params().video_params().frame_rate_as_time_base().toAVRational();
codec_ctx->framerate =
params().video_params().frame_rate().toAVRational();
codec_ctx->pix_fmt = av_get_pix_fmt(params().video_pix_fmt().toUtf8());
codec_ctx->color_range = params().video_params().color_range() == VideoParams::kColorRangeFull ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
codec_ctx->color_range = params().video_params().color_range() ==
VideoParams::kColorRangeFull ?
AVCOL_RANGE_JPEG :
AVCOL_RANGE_MPEG;
if (params().video_params().interlacing() != VideoParams::kInterlaceNone) {
if (params().video_params().interlacing() !=
VideoParams::kInterlaceNone) {
// FIXME: I actually don't know what these flags do, the documentation helpfully doesn't
// explain them at all. I hope using both of them is the right thing to do.
codec_ctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME;
codec_ctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT |
AV_CODEC_FLAG_INTERLACED_ME;
if (params().video_params().interlacing() == VideoParams::kInterlacedTopFirst) {
if (params().video_params().interlacing() ==
VideoParams::kInterlacedTopFirst) {
codec_ctx->field_order = AV_FIELD_TT;
} else {
codec_ctx->field_order = AV_FIELD_BB;
if (codec == ExportCodec::kCodecH264 || codec == ExportCodec::kCodecH264rgb) {
if (codec == ExportCodec::kCodecH264 ||
codec == ExportCodec::kCodecH264rgb) {
// For some reason, FFmpeg doesn't set libx264's bff flag so we have to do it ourselves
av_opt_set(codec_ctx->priv_data, "x264opts", "bff=1", AV_OPT_SEARCH_CHILDREN);
av_opt_set(codec_ctx->priv_data, "x264opts", "bff=1",
AV_OPT_SEARCH_CHILDREN);
}
}
}
// Set custom options
{
for (auto i=params().video_opts().begin();i!=params().video_opts().end();i++) {
for (auto i = params().video_opts().begin();
i != params().video_opts().end(); i++) {
if (!i.key().startsWith(QStringLiteral("ove_"))) {
av_opt_set(codec_ctx->priv_data, i.key().toUtf8(), i.value().toUtf8(), AV_OPT_SEARCH_CHILDREN);
av_opt_set(codec_ctx->priv_data, i.key().toUtf8(),
i.value().toUtf8(), AV_OPT_SEARCH_CHILDREN);
}
}
@@ -670,12 +746,14 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV
}
if (params().video_buffer_size() > 0) {
codec_ctx->rc_buffer_size = static_cast<int>(params().video_buffer_size());
codec_ctx->rc_buffer_size =
static_cast<int>(params().video_buffer_size());
}
// nclc tags. See https://ffmpeg.org/doxygen/4.0/pixfmt_8h.html#ad384ee5a840bafd73daef08e6d9cafe7
// ffprobe -v error -show_format -show_streams "C:\Users\Tom\Documents\srgb correct tags.mov"
if (params().color_transform().output().contains(QStringLiteral("sRGB"), Qt::CaseInsensitive)) {
if (params().color_transform().output().contains(
QStringLiteral("sRGB"), Qt::CaseInsensitive)) {
codec_ctx->color_primaries = AVCOL_PRI_BT709;
codec_ctx->color_trc = AVCOL_TRC_IEC61966_2_1;
codec_ctx->colorspace = AVCOL_SPC_BT709;
@@ -687,11 +765,11 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV
}
} else if (type == AVMEDIA_TYPE_AUDIO) {
// Assume audio stream
codec_ctx->sample_rate = params().audio_params().sample_rate();
codec_ctx->ch_layout = params().audio_params().channel_layout();
codec_ctx->sample_fmt = FFmpegUtils::GetFFmpegSampleFormat(params().audio_params().format());
codec_ctx->sample_fmt = FFmpegUtils::GetFFmpegSampleFormat(
params().audio_params().format());
codec_ctx->time_base = { 1, codec_ctx->sample_rate };
if (params().audio_bit_rate() > 0) {
@@ -699,14 +777,13 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV
}
} else if (type == AVMEDIA_TYPE_SUBTITLE) {
codec_ctx->time_base = av_get_time_base_q();
QByteArray ass_header = SubtitleParams::GenerateASSHeader().toUtf8();
codec_ctx->subtitle_header = new uint8_t[ass_header.size()];
memcpy(codec_ctx->subtitle_header, ass_header.constData(), ass_header.size());
memcpy(codec_ctx->subtitle_header, ass_header.constData(),
ass_header.size());
codec_ctx->subtitle_header_size = ass_header.size();
}
if (!SetupCodecContext(stream, codec_ctx, encoder)) {
@@ -716,7 +793,9 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV
return true;
}
bool FFmpegEncoder::InitializeCodecContext(AVStream **stream, AVCodecContext **codec_ctx, const AVCodec* codec)
bool FFmpegEncoder::InitializeCodecContext(AVStream **stream,
AVCodecContext **codec_ctx,
const AVCodec *codec)
{
*stream = avformat_new_stream(fmt_ctx_, nullptr);
if (!(*stream)) {
@@ -734,7 +813,9 @@ bool FFmpegEncoder::InitializeCodecContext(AVStream **stream, AVCodecContext **c
return true;
}
bool FFmpegEncoder::SetupCodecContext(AVStream* stream, AVCodecContext* codec_ctx, const AVCodec* codec)
bool FFmpegEncoder::SetupCodecContext(AVStream *stream,
AVCodecContext *codec_ctx,
const AVCodec *codec)
{
int error_code;
@@ -762,7 +843,8 @@ bool FFmpegEncoder::SetupCodecContext(AVStream* stream, AVCodecContext* codec_ct
// Copy context settings to codecpar object
error_code = avcodec_parameters_from_context(stream->codecpar, codec_ctx);
if (error_code < 0) {
FFmpegError(tr("Failed to copy codec parameters to stream"), error_code);
FFmpegError(tr("Failed to copy codec parameters to stream"),
error_code);
return false;
}
@@ -828,15 +910,11 @@ bool FFmpegEncoder::InitializeResampleContext(const AudioParams &audio)
}
AVChannelLayout layout = audio.channel_layout();
// Create resample context
swr_alloc_set_opts2(&audio_resample_ctx_,
&audio_codec_ctx_->ch_layout,
swr_alloc_set_opts2(&audio_resample_ctx_, &audio_codec_ctx_->ch_layout,
audio_codec_ctx_->sample_fmt,
audio_codec_ctx_->sample_rate,
&layout,
audio_codec_ctx_->sample_rate, &layout,
FFmpegUtils::GetFFmpegSampleFormat(audio.format()),
audio.sample_rate(),
0,
nullptr);
audio.sample_rate(), 0, nullptr);
if (!audio_resample_ctx_) {
return false;
}
@@ -852,7 +930,8 @@ bool FFmpegEncoder::InitializeResampleContext(const AudioParams &audio)
// If not, use another frame size
if (params().video_enabled()) {
// If we're encoding video, use enough samples to cover roughly one frame of video
audio_max_samples_ = params().audio_params().time_to_samples(params().video_params().frame_rate_as_time_base());
audio_max_samples_ = params().audio_params().time_to_samples(
params().video_params().frame_rate_as_time_base());
} else {
// If no video, just use an arbitrary number
audio_max_samples_ = 256;
@@ -880,7 +959,8 @@ bool FFmpegEncoder::InitializeResampleContext(const AudioParams &audio)
return true;
}
const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c, SampleFormat aformat)
const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c,
SampleFormat aformat)
{
switch (c) {
case ExportCodec::kCodecH264:
+22 -13
View File
@@ -31,25 +31,29 @@ extern "C" {
#include "codec/encoder.h"
namespace olive {
class FFmpegEncoder : public Encoder
namespace olive
{
class FFmpegEncoder : public Encoder {
Q_OBJECT
public:
FFmpegEncoder(const EncodingParams &params);
virtual QStringList GetPixelFormatsForCodec(ExportCodec::Codec c) const override;
virtual QStringList
GetPixelFormatsForCodec(ExportCodec::Codec c) const override;
virtual std::vector<SampleFormat> GetSampleFormatsForCodec(ExportCodec::Codec c) const override;
virtual std::vector<SampleFormat>
GetSampleFormatsForCodec(ExportCodec::Codec c) const override;
virtual bool Open() override;
virtual bool WriteFrame(olive::FramePtr frame, olive::core::rational time) override;
virtual bool WriteFrame(olive::FramePtr frame,
olive::core::rational time) override;
virtual bool WriteAudio(const olive::SampleBuffer &audio) override;
bool WriteAudioData(const AudioParams &audio_params, const uint8_t **data, int input_sample_count);
bool WriteAudioData(const AudioParams &audio_params, const uint8_t **data,
int input_sample_count);
virtual bool WriteSubtitle(const SubtitleBlock *sub_block) override;
@@ -71,18 +75,24 @@ private:
*/
void FFmpegError(const QString &context, int error_code);
bool WriteAVFrame(AVFrame* frame, AVCodecContext *codec_ctx, AVStream *stream);
bool WriteAVFrame(AVFrame *frame, AVCodecContext *codec_ctx,
AVStream *stream);
bool InitializeStream(enum AVMediaType type, AVStream** stream, AVCodecContext** codec_ctx, const ExportCodec::Codec &codec);
bool InitializeCodecContext(AVStream** stream, AVCodecContext** codec_ctx, const AVCodec* codec);
bool SetupCodecContext(AVStream *stream, AVCodecContext *codec_ctx, const AVCodec *codec);
bool InitializeStream(enum AVMediaType type, AVStream **stream,
AVCodecContext **codec_ctx,
const ExportCodec::Codec &codec);
bool InitializeCodecContext(AVStream **stream, AVCodecContext **codec_ctx,
const AVCodec *codec);
bool SetupCodecContext(AVStream *stream, AVCodecContext *codec_ctx,
const AVCodec *codec);
void FlushEncoders();
void FlushCodecCtx(AVCodecContext *codec_ctx, AVStream *stream);
bool InitializeResampleContext(const AudioParams &audio);
static const AVCodec *GetEncoder(ExportCodec::Codec c, SampleFormat aformat);
static const AVCodec *GetEncoder(ExportCodec::Codec c,
SampleFormat aformat);
AVFormatContext *fmt_ctx_;
@@ -105,7 +115,6 @@ private:
AVCodecContext *subtitle_codec_ctx_;
bool open_;
};
}
+27 -19
View File
@@ -28,12 +28,13 @@
#include "common/oiioutils.h"
#include "render/framemanager.h"
namespace olive {
namespace olive
{
Frame::Frame() :
data_(nullptr),
data_size_(0),
timestamp_(0)
Frame::Frame()
: data_(nullptr)
, data_size_(0)
, timestamp_(0)
{
}
@@ -56,14 +57,16 @@ void Frame::set_video_params(const VideoParams &params)
{
params_ = params;
linesize_ = generate_linesize_bytes(width(), params_.format(), params_.channel_count());
linesize_ = generate_linesize_bytes(width(), params_.format(),
params_.channel_count());
linesize_pixels_ = linesize_ / params_.GetBytesPerPixel();
}
FramePtr Frame::Interlace(FramePtr top, FramePtr bottom)
{
if (top->video_params() != bottom->video_params()) {
qCritical() << "Tried to interlace two frames that had incompatible parameters";
qCritical()
<< "Tried to interlace two frames that had incompatible parameters";
return nullptr;
}
@@ -77,17 +80,18 @@ FramePtr Frame::Interlace(FramePtr top, FramePtr bottom)
FramePtr which = (i % 2 == 0) ? top : bottom;
memcpy(interlaced->data() + i * linesize,
which->const_data() + i*linesize,
linesize);
which->const_data() + i * linesize, linesize);
}
return interlaced;
}
int Frame::generate_linesize_bytes(int width, PixelFormat format, int channel_count)
int Frame::generate_linesize_bytes(int width, PixelFormat format,
int channel_count)
{
// Align to 32 bytes (not sure if this is necessary?)
return VideoParams::GetBytesPerPixel(format, channel_count) * ((width + 31) & ~31);
return VideoParams::GetBytesPerPixel(format, channel_count) *
((width + 31) & ~31);
}
Color Frame::get_pixel(int x, int y) const
@@ -96,9 +100,11 @@ Color Frame::get_pixel(int x, int y) const
return Color();
}
int byte_offset = y * linesize_bytes() + x * video_params().GetBytesPerPixel();
int byte_offset =
y * linesize_bytes() + x * video_params().GetBytesPerPixel();
return Color(reinterpret_cast<const char*>(data_ + byte_offset), video_params().format(), video_params().channel_count());
return Color(reinterpret_cast<const char *>(data_ + byte_offset),
video_params().format(), video_params().channel_count());
}
bool Frame::contains_pixel(int x, int y) const
@@ -112,9 +118,11 @@ void Frame::set_pixel(int x, int y, const Color &c)
return;
}
int byte_offset = y * linesize_bytes() + x * video_params().GetBytesPerPixel();
int byte_offset =
y * linesize_bytes() + x * video_params().GetBytesPerPixel();
c.toData(reinterpret_cast<char*>(data_ + byte_offset), video_params().format(), video_params().channel_count());
c.toData(reinterpret_cast<char *>(data_ + byte_offset),
video_params().format(), video_params().channel_count());
}
bool Frame::allocate()
@@ -159,14 +167,14 @@ FramePtr Frame::convert(PixelFormat format) const
converted->allocate();
// Do the conversion through OIIO for convenience
OIIO::ImageBuf src(OIIO::ImageSpec(width(), height(),
channel_count(),
OIIO::ImageBuf src(
OIIO::ImageSpec(width(), height(), channel_count(),
OIIOUtils::GetOIIOBaseTypeFromFormat(this->format())));
OIIOUtils::FrameToBuffer(this, &src);
OIIO::ImageBuf dst(OIIO::ImageSpec(converted->width(), converted->height(),
channel_count(),
OIIO::ImageBuf dst(OIIO::ImageSpec(
converted->width(), converted->height(), channel_count(),
OIIOUtils::GetOIIOBaseTypeFromFormat(format)));
if (dst.copy_pixels(src)) {
+5 -5
View File
@@ -28,7 +28,8 @@
#include "common/define.h"
#include "render/videoparams.h"
namespace olive {
namespace olive
{
class Frame;
using FramePtr = std::shared_ptr<Frame>;
@@ -36,8 +37,7 @@ using FramePtr = std::shared_ptr<Frame>;
/**
* @brief Video frame data or audio sample data from a Decoder
*/
class Frame
{
class Frame {
public:
Frame();
@@ -52,7 +52,8 @@ public:
static FramePtr Interlace(FramePtr top, FramePtr bottom);
static int generate_linesize_bytes(int width, PixelFormat format, int channel_count);
static int generate_linesize_bytes(int width, PixelFormat format,
int channel_count);
int linesize_pixels() const
{
@@ -164,7 +165,6 @@ private:
int linesize_;
int linesize_pixels_;
};
}
+37 -20
View File
@@ -31,12 +31,13 @@
#include "core.h"
#include "render/renderer.h"
namespace olive {
namespace olive
{
QStringList OIIODecoder::supported_formats_;
OIIODecoder::OIIODecoder() :
image_(nullptr)
OIIODecoder::OIIODecoder()
: image_(nullptr)
{
}
@@ -45,7 +46,8 @@ QString OIIODecoder::id() const
return QStringLiteral("oiio");
}
FootageDescription OIIODecoder::Probe(const QString &filename, CancelAtom *cancelled) const
FootageDescription OIIODecoder::Probe(const QString &filename,
CancelAtom *cancelled) const
{
Q_UNUSED(cancelled)
@@ -85,8 +87,10 @@ FootageDescription OIIODecoder::Probe(const QString &filename, CancelAtom *cance
// This is a multilayer image and this image might have an offset
OIIO::ImageSpec root_spec = in->spec(0);
float norm_x = spec.x + float(spec.width)*0.5f - float(root_spec.width)*0.5f;
float norm_y = spec.y + float(spec.height)*0.5f - float(root_spec.height)*0.5f;
float norm_x = spec.x + float(spec.width) * 0.5f -
float(root_spec.width) * 0.5f;
float norm_y = spec.y + float(spec.height) * 0.5f -
float(root_spec.height) * 0.5f;
video_params.set_x(norm_x);
video_params.set_y(norm_y);
@@ -124,8 +128,7 @@ TexturePtr OIIODecoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
VideoParams vp = GetVideoParamsFromImageSpec(image_->spec());
vp.set_divider(p.divider);
if (!buffer_.is_allocated()
|| last_params_.divider != p.divider) {
if (!buffer_.is_allocated() || last_params_.divider != p.divider) {
last_params_ = p;
buffer_.destroy();
@@ -137,7 +140,9 @@ TexturePtr OIIODecoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
image_->read_image(0, 0, 0, -1, oiio_pix_fmt_, buffer_.data());
} else {
OIIO::ImageBuf buf(image_->spec());
image_->read_image(0,0,0,-1,image_->spec().format, buf.localpixels(), buf.pixel_stride(), buf.scanline_stride(), buf.z_stride());
image_->read_image(0, 0, 0, -1, image_->spec().format,
buf.localpixels(), buf.pixel_stride(),
buf.scanline_stride(), buf.z_stride());
// Roughly downsample image for divider (for some reason OIIO::ImageBufAlgo::resample failed here)
int px_sz = vp.GetBytesPerPixel();
@@ -146,15 +151,18 @@ TexturePtr OIIODecoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
for (int dst_x = 0; dst_x < buffer_.width(); dst_x++) {
int src_x = dst_x * buf.spec().width / buffer_.width();
memcpy(buffer_.data() + buffer_.linesize_bytes() * dst_y + px_sz * dst_x,
static_cast<uint8_t*>(buf.localpixels()) + buf.scanline_stride() * src_y + px_sz * src_x,
memcpy(buffer_.data() + buffer_.linesize_bytes() * dst_y +
px_sz * dst_x,
static_cast<uint8_t *>(buf.localpixels()) +
buf.scanline_stride() * src_y + px_sz * src_x,
px_sz);
}
}
}
}
return p.renderer->CreateTexture(vp, buffer_.data(), buffer_.linesize_pixels());
return p.renderer->CreateTexture(vp, buffer_.data(),
buffer_.linesize_pixels());
}
void OIIODecoder::CloseInternal()
@@ -170,7 +178,9 @@ bool OIIODecoder::FileTypeIsSupported(const QString& fn)
// Check if we've created the supported formats list, create it if not
if (supported_formats_.isEmpty()) {
QStringList extension_list = QString::fromStdString(OIIO::get_string_attribute("extension_list")).split(';');
QStringList extension_list =
QString::fromStdString(OIIO::get_string_attribute("extension_list"))
.split(';');
// The format of "extension_list" is "format:ext", we want to separate it into a simple list of extensions
foreach (const QString &ext, extension_list) {
@@ -180,7 +190,8 @@ bool OIIODecoder::FileTypeIsSupported(const QString& fn)
}
}
if (!supported_formats_.contains(QFileInfo(fn).suffix(), Qt::CaseInsensitive)) {
if (!supported_formats_.contains(QFileInfo(fn).suffix(),
Qt::CaseInsensitive)) {
return false;
}
@@ -203,17 +214,20 @@ bool OIIODecoder::OpenImageHandler(const QString &fn, int subimage)
const OIIO::ImageSpec &spec = image_->spec();
// We use RGBA frames because that tends to be the native format of GPUs
pix_fmt_ = OIIOUtils::GetFormatFromOIIOBasetype(static_cast<OIIO::TypeDesc::BASETYPE>(spec.format.basetype));
pix_fmt_ = OIIOUtils::GetFormatFromOIIOBasetype(
static_cast<OIIO::TypeDesc::BASETYPE>(spec.format.basetype));
if (pix_fmt_ == PixelFormat::INVALID) {
qWarning() << "Failed to convert OIIO::ImageDesc to native pixel format";
qWarning()
<< "Failed to convert OIIO::ImageDesc to native pixel format";
return false;
}
oiio_pix_fmt_ = OIIOUtils::GetOIIOBaseTypeFromFormat(pix_fmt_);
if (oiio_pix_fmt_ == OIIO::TypeDesc::UNKNOWN) {
qCritical() << "Failed to determine appropriate OIIO basetype from native format";
qCritical()
<< "Failed to determine appropriate OIIO basetype from native format";
return false;
}
@@ -230,15 +244,18 @@ void OIIODecoder::CloseImageHandle()
buffer_.destroy();
}
VideoParams OIIODecoder::GetVideoParamsFromImageSpec(const OIIO::ImageSpec &spec)
VideoParams
OIIODecoder::GetVideoParamsFromImageSpec(const OIIO::ImageSpec &spec)
{
VideoParams video_params;
video_params.set_width(spec.width);
video_params.set_height(spec.height);
video_params.set_format(OIIOUtils::GetFormatFromOIIOBasetype(static_cast<OIIO::TypeDesc::BASETYPE>(spec.format.basetype)));
video_params.set_format(OIIOUtils::GetFormatFromOIIOBasetype(
static_cast<OIIO::TypeDesc::BASETYPE>(spec.format.basetype)));
video_params.set_channel_count(spec.nchannels);
video_params.set_pixel_aspect_ratio(OIIOUtils::GetPixelAspectRatioFromOIIO(spec));
video_params.set_pixel_aspect_ratio(
OIIOUtils::GetPixelAspectRatioFromOIIO(spec));
video_params.set_video_type(VideoParams::kVideoTypeStill);
return video_params;
+11 -7
View File
@@ -26,10 +26,10 @@
#include "codec/decoder.h"
namespace olive {
class OIIODecoder : public Decoder
namespace olive
{
class OIIODecoder : public Decoder {
Q_OBJECT
public:
OIIODecoder();
@@ -38,13 +38,18 @@ public:
virtual QString id() const override;
virtual bool SupportsVideo() override{return true;}
virtual bool SupportsVideo() override
{
return true;
}
virtual FootageDescription Probe(const QString& filename, CancelAtom *cancelled) const override;
virtual FootageDescription Probe(const QString &filename,
CancelAtom *cancelled) const override;
protected:
virtual bool OpenInternal() override;
virtual TexturePtr RetrieveVideoInternal(const RetrieveVideoParams& p) override;
virtual TexturePtr
RetrieveVideoInternal(const RetrieveVideoParams &p) override;
virtual void CloseInternal() override;
private:
@@ -65,7 +70,6 @@ private:
RetrieveVideoParams last_params_;
static QStringList supported_formats_;
};
}
+8 -6
View File
@@ -22,12 +22,12 @@
#include "common/oiioutils.h"
namespace olive {
OIIOEncoder::OIIOEncoder(const EncodingParams &params) :
Encoder(params)
namespace olive
{
OIIOEncoder::OIIOEncoder(const EncodingParams &params)
: Encoder(params)
{
}
bool OIIOEncoder::Open()
@@ -45,13 +45,15 @@ bool OIIOEncoder::WriteFrame(FramePtr frame, rational time)
}
OIIO::TypeDesc type = OIIOUtils::GetOIIOBaseTypeFromFormat(frame->format());
OIIO::ImageSpec spec(frame->width(), frame->height(), frame->channel_count(), type);
OIIO::ImageSpec spec(frame->width(), frame->height(),
frame->channel_count(), type);
if (!output->open(filename, spec)) {
return false;
}
if (!output->write_image(type, frame->data(), OIIO::AutoStride, frame->linesize_bytes())) {
if (!output->write_image(type, frame->data(), OIIO::AutoStride,
frame->linesize_bytes())) {
return false;
}
+5 -5
View File
@@ -23,10 +23,10 @@
#include "codec/encoder.h"
namespace olive {
class OIIOEncoder : public Encoder
namespace olive
{
class OIIOEncoder : public Encoder {
Q_OBJECT
public:
OIIOEncoder(const EncodingParams &params);
@@ -34,12 +34,12 @@ public:
public slots:
virtual bool Open() override;
virtual bool WriteFrame(olive::FramePtr frame, olive::core::rational time) override;
virtual bool WriteFrame(olive::FramePtr frame,
olive::core::rational time) override;
virtual bool WriteAudio(const SampleBuffer &audio) override;
virtual bool WriteSubtitle(const SubtitleBlock *sub_block) override;
virtual void Close() override;
};
}
+10 -7
View File
@@ -20,12 +20,12 @@
#include "planarfiledevice.h"
namespace olive {
PlanarFileDevice::PlanarFileDevice(QObject *parent) :
QObject(parent)
namespace olive
{
PlanarFileDevice::PlanarFileDevice(QObject *parent)
: QObject(parent)
{
}
PlanarFileDevice::~PlanarFileDevice()
@@ -33,7 +33,8 @@ PlanarFileDevice::~PlanarFileDevice()
close();
}
bool PlanarFileDevice::open(const QVector<QString> &filenames, QIODevice::OpenMode mode)
bool PlanarFileDevice::open(const QVector<QString> &filenames,
QIODevice::OpenMode mode)
{
if (isOpen()) {
// Already open
@@ -54,7 +55,8 @@ bool PlanarFileDevice::open(const QVector<QString> &filenames, QIODevice::OpenMo
return true;
}
qint64 PlanarFileDevice::read(char **data, qint64 bytes_per_channel, qint64 offset)
qint64 PlanarFileDevice::read(char **data, qint64 bytes_per_channel,
qint64 offset)
{
qint64 ret = -1;
@@ -68,7 +70,8 @@ qint64 PlanarFileDevice::read(char **data, qint64 bytes_per_channel, qint64 offs
return ret;
}
qint64 PlanarFileDevice::write(const char **data, qint64 bytes_per_channel, qint64 offset)
qint64 PlanarFileDevice::write(const char **data, qint64 bytes_per_channel,
qint64 offset)
{
qint64 ret = -1;
+5 -5
View File
@@ -25,12 +25,12 @@
#include <QFile>
#include <QObject>
namespace olive {
namespace olive
{
using namespace core;
class PlanarFileDevice : public QObject
{
class PlanarFileDevice : public QObject {
Q_OBJECT
public:
PlanarFileDevice(QObject *parent = nullptr);
@@ -46,7 +46,8 @@ public:
qint64 read(char **data, qint64 bytes_per_channel, qint64 offset = 0);
qint64 write(const char **data, qint64 bytes_per_channel, qint64 offset = 0);
qint64 write(const char **data, qint64 bytes_per_channel,
qint64 offset = 0);
qint64 size() const;
@@ -56,7 +57,6 @@ public:
private:
QVector<QFile *> files_;
};
}
+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 };
};
}
+5 -3
View File
@@ -24,7 +24,8 @@
#include "common/define.h"
#include "render/cancelatom.h"
namespace olive {
namespace olive
{
class CancelableObject {
public:
@@ -49,11 +50,12 @@ public:
}
protected:
virtual void CancelEvent(){}
virtual void CancelEvent()
{
}
private:
CancelAtom cancel_;
};
}
+15 -7
View File
@@ -34,16 +34,23 @@ CommandLineParser::~CommandLineParser()
}
}
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();
options_.append({strings, description, o, takes_arg, arg_placeholder, hidden});
options_.append(
{ strings, description, o, takes_arg, arg_placeholder, hidden });
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();
@@ -103,8 +110,7 @@ found_flag:
void CommandLineParser::PrintHelp(const char *filename)
{
printf("%s %s\n",
QCoreApplication::applicationName().toUtf8().constData(),
printf("%s %s\n", QCoreApplication::applicationName().toUtf8().constData(),
QCoreApplication::applicationVersion().toUtf8().constData());
printf("Copyright (C) 2018-2022 Olive Team\n");
@@ -138,7 +144,8 @@ void CommandLineParser::PrintHelp(const char* filename)
basename = filename;
}
printf("Usage: %s [options] %s\n\n", basename, positional_args.toUtf8().constData());
printf("Usage: %s [options] %s\n\n", basename,
positional_args.toUtf8().constData());
foreach (const KnownOption &o, options_) {
if (o.hidden) {
continue;
@@ -160,7 +167,8 @@ void CommandLineParser::PrintHelp(const char* filename)
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 <%s>\n", all_args.toUtf8().constData(),
o.arg_placeholder.toUtf8().constData());
}
printf(" %s\n\n", o.description.toUtf8().constData());
+9 -9
View File
@@ -36,15 +36,13 @@
* 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();
DISABLE_COPY_MOVE(CommandLineParser)
class PositionalArgument
{
class PositionalArgument {
public:
PositionalArgument() = default;
@@ -60,7 +58,6 @@ public:
private:
QString setting_;
};
class Option : public PositionalArgument {
@@ -82,14 +79,18 @@ public:
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);
const Option *AddOption(const QStringList &strings,
const QString &description, bool takes_arg = false,
const QString &arg_placeholder = QString(),
bool hidden = false);
const PositionalArgument* AddPositionalArgument(const QString& name, const QString& description, bool required = false);
const PositionalArgument *AddPositionalArgument(const QString &name,
const QString &description,
bool required = false);
void Process(const QVector<QString> &argv);
@@ -115,7 +116,6 @@ private:
QVector<KnownOption> options_;
QVector<KnownPositionalArgument> positional_args_;
};
#endif // COMMANDLINEPARSER_H
+22 -11
View File
@@ -40,12 +40,16 @@ 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);
QString handler_abs_path =
QDir(QCoreApplication::applicationDirPath()).filePath(handler_fn);
bool status = false;
@@ -54,7 +58,9 @@ bool InitializeCrashpad()
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;
@@ -65,24 +71,29 @@ bool InitializeCrashpad()
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;
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;
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);
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";
qWarning()
<< "Failed to start Crashpad, automatic crash reporting will be disabled";
}
return status;
+4 -2
View File
@@ -20,9 +20,11 @@
#include "debug.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)
{
QByteArray localMsg = msg.toLocal8Bit();
+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);
}
+3 -4
View File
@@ -26,10 +26,10 @@
//#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;
@@ -96,7 +96,6 @@ public:
private:
static constexpr double LOG100 = 4.60517018599;
};
}
+8 -4
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,9 +40,12 @@ 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
+2 -1
View File
@@ -23,7 +23,8 @@
#include <stdint.h>
namespace olive {
namespace olive
{
inline int64_t GetDigitCount(int64_t input)
{
+18 -11
View File
@@ -20,9 +20,12 @@
#include "common/ffmpegutils.h"
namespace olive {
namespace olive
{
AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt, PixelFormat maximum)
AVPixelFormat
FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt,
PixelFormat maximum)
{
AVPixelFormat possible_pix_fmts[3];
@@ -35,9 +38,7 @@ AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt
possible_pix_fmts[2] = AV_PIX_FMT_NONE;
}
return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts,
pix_fmt,
1,
return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts, pix_fmt, 1,
nullptr);
}
@@ -136,11 +137,16 @@ int FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVColorSpace cs)
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;
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;
}
@@ -148,7 +154,8 @@ AVPixelFormat FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AVPixelFormat 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) {
+7 -3
View File
@@ -31,7 +31,8 @@ extern "C" {
#include "render/videoparams.h"
namespace olive {
namespace olive
{
using namespace core;
@@ -40,7 +41,9 @@ 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
@@ -50,7 +53,8 @@ public:
/**
* @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
+36 -19
View File
@@ -29,7 +29,8 @@
#include "config/config.h"
namespace olive {
namespace olive
{
QString FileFunctions::GetUniqueFileIdentifier(const QString &filename)
{
@@ -43,7 +44,8 @@ QString FileFunctions::GetUniqueFileIdentifier(const QString &filename)
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();
@@ -55,7 +57,8 @@ QString FileFunctions::GetConfigurationLocation()
if (IsPortable()) {
return GetApplicationPath();
} else {
QString s = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QString s =
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir(s).mkpath(".");
return s;
}
@@ -73,7 +76,9 @@ QString FileFunctions::GetApplicationPath()
QString FileFunctions::GetTempFilePath()
{
QString temp_path = QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation))
QString temp_path =
QDir(
QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation))
.filePath(QCoreApplication::organizationName()))
.filePath(QCoreApplication::applicationName());
@@ -83,20 +88,23 @@ QString FileFunctions::GetTempFilePath()
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();
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("..")) {
if (info.fileName() == QStringLiteral(".") ||
info.fileName() == QStringLiteral("..")) {
continue;
}
QString dest_equivalent = QDir(dest).filePath(info.fileName());
if (info.isDir()) {
if (!CanCopyDirectoryWithoutOverwriting(info.absoluteFilePath(), dest_equivalent)) {
if (!CanCopyDirectoryWithoutOverwriting(info.absoluteFilePath(),
dest_equivalent)) {
return false;
}
} else if (QFileInfo::exists(dest_equivalent)) {
@@ -107,12 +115,14 @@ bool FileFunctions::CanCopyDirectoryWithoutOverwriting(const QString& source, co
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);
if (!d.exists()) {
qCritical() << "Failed to copy directory, source" << source << "didn't exist";
qCritical()
<< "Failed to copy directory, source" << source << "didn't exist";
return;
}
@@ -127,7 +137,8 @@ void FileFunctions::CopyDirectory(const QString &source, const QString &dest, bo
foreach (const QFileInfo &info, l) {
// QDir::NoDotAndDotDot continues to not work, so we have to check manually
if (info.fileName() == QStringLiteral(".") || info.fileName() == QStringLiteral("..")) {
if (info.fileName() == QStringLiteral(".") ||
info.fileName() == QStringLiteral("..")) {
continue;
}
@@ -140,8 +151,10 @@ void FileFunctions::CopyDirectory(const QString &source, const QString &dest, bo
// 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.setPermissions(
file.permissions() | QFileDevice::WriteOwner |
QFileDevice::WriteUser | QFileDevice::WriteGroup |
QFileDevice::WriteOther);
file.remove();
}
@@ -150,13 +163,15 @@ void FileFunctions::CopyDirectory(const QString &source, const QString &dest, bo
}
}
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("."));
}
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()) {
@@ -201,16 +216,16 @@ QString FileFunctions::GetSafeTemporaryFilename(const QString &original)
QString temp_abs_path;
do {
temp_abs_path = original_info.dir().filePath(
QStringLiteral("%1.tmp%2%3").arg(basename,
QString::number(counter),
complete_suffix));
QStringLiteral("%1.tmp%2%3")
.arg(basename, QString::number(counter), complete_suffix));
counter++;
} while (QFileInfo::exists(temp_abs_path));
return temp_abs_path;
}
bool FileFunctions::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";
@@ -228,7 +243,9 @@ bool FileFunctions::RenameFileAllowOverwrite(const QString &from, const QString
QString FileFunctions::GetAutoRecoveryRoot()
{
return QDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(QStringLiteral("autorecovery"));
return QDir(QStandardPaths::writableLocation(
QStandardPaths::AppLocalDataLocation))
.filePath(QStringLiteral("autorecovery"));
}
}
+12 -9
View File
@@ -26,7 +26,8 @@
#include "common/define.h"
namespace olive {
namespace olive
{
/**
* @brief A collection of static file and directory functions
@@ -49,11 +50,14 @@ public:
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
@@ -64,7 +68,8 @@ 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);
@@ -83,7 +88,8 @@ public:
/**
* @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)
{
@@ -95,11 +101,8 @@ public:
}
static QString GetAutoRecoveryRoot();
};
}
#endif // FILEFUNCTIONS_H
+58 -32
View File
@@ -5,12 +5,11 @@
#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)
{
@@ -71,14 +70,14 @@ void Html::HtmlToDoc(QTextDocument *doc, const QString &html)
reader.readNext();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
QString tag = reader.name().toString().toLower();
fmt_stack.append({ tag, ReadCharFormat(reader.attributes()) });
current_fmt = MergeHtmlFormats(fmt_stack);
if (kBlockTags.contains(tag)) {
QTextBlockFormat block_fmt = ReadBlockFormat(reader.attributes());
QTextBlockFormat block_fmt =
ReadBlockFormat(reader.attributes());
if (inside_block) {
c.setBlockFormat(block_fmt);
c.setBlockCharFormat(current_fmt);
@@ -89,12 +88,10 @@ void Html::HtmlToDoc(QTextDocument *doc, const QString &html)
}
} else if (reader.tokenType() == QXmlStreamReader::Characters) {
QString characters = reader.text().toString();
c.insertText(characters, current_fmt);
} else if (reader.tokenType() == QXmlStreamReader::EndElement) {
QString tag = reader.name().toString().toLower();
for (int i = fmt_stack.size() - 1; i >= 0; i--) {
@@ -108,7 +105,6 @@ void Html::HtmlToDoc(QTextDocument *doc, const QString &html)
break;
}
}
}
}
@@ -126,11 +122,14 @@ void Html::WriteBlock(QXmlStreamWriter *writer, const QTextBlock &block)
// Write block alignment
if (!(fmt.alignment() & Qt::AlignLeft)) {
if (fmt.alignment() & Qt::AlignRight) {
writer->writeAttribute(QStringLiteral("align"), QStringLiteral("right"));
writer->writeAttribute(QStringLiteral("align"),
QStringLiteral("right"));
} else if (fmt.alignment() & Qt::AlignHCenter) {
writer->writeAttribute(QStringLiteral("align"), QStringLiteral("center"));
writer->writeAttribute(QStringLiteral("align"),
QStringLiteral("center"));
} else if (fmt.alignment() & Qt::AlignJustify) {
writer->writeAttribute(QStringLiteral("align"), QStringLiteral("justify"));
writer->writeAttribute(QStringLiteral("align"),
QStringLiteral("justify"));
}
}
@@ -143,7 +142,8 @@ void Html::WriteBlock(QXmlStreamWriter *writer, const QTextBlock &block)
QString style;
if (fmt.lineHeightType() != QTextBlockFormat::SingleHeight) {
WriteCSSProperty(&style, QStringLiteral("line-height"), QStringLiteral("%1%").arg(fmt.lineHeight()));
WriteCSSProperty(&style, QStringLiteral("line-height"),
QStringLiteral("%1%").arg(fmt.lineHeight()));
}
WriteCharFormat(&style, block.charFormat());
@@ -163,7 +163,8 @@ void Html::WriteBlock(QXmlStreamWriter *writer, const QTextBlock &block)
writer->writeEndElement(); // p
}
void Html::WriteFragment(QXmlStreamWriter *writer, const QTextFragment &fragment)
void Html::WriteFragment(QXmlStreamWriter *writer,
const QTextFragment &fragment)
{
const QTextCharFormat &fmt = fragment.charFormat();
@@ -192,7 +193,8 @@ void Html::WriteFragment(QXmlStreamWriter *writer, const QTextFragment &fragment
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) {
@@ -210,23 +212,30 @@ void Html::WriteCharFormat(QString *style, const QTextCharFormat &fmt)
{
QStringList families = fmt.fontFamilies().toStringList();
if (!families.isEmpty()) {
WriteCSSProperty(style, QStringLiteral("font-family"), families.first());
WriteCSSProperty(style, QStringLiteral("font-family"),
families.first());
}
if (fmt.hasProperty(QTextFormat::FontPointSize)) {
WriteCSSProperty(style, QStringLiteral("font-size"), QStringLiteral("%1pt").arg(QString::number(fmt.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));
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"));
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());
WriteCSSProperty(style, QStringLiteral("-ove-font-style"),
fmt.fontStyleName().toString());
}
QStringList deco;
@@ -254,7 +263,11 @@ void Html::WriteCharFormat(QString *style, const QTextCharFormat &fmt)
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()));
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);
@@ -262,17 +275,22 @@ void Html::WriteCharFormat(QString *style, const QTextCharFormat &fmt)
if (fmt.fontCapitalization() != QFont::MixedCase) {
if (fmt.fontCapitalization() == QFont::SmallCaps) {
WriteCSSProperty(style, QStringLiteral("font-variant"), QStringLiteral("small-caps"));
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())));
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())));
WriteCSSProperty(
style, QStringLiteral("font-stretch"),
QStringLiteral("%1%").arg(QString::number(fmt.fontStretch())));
}
}
@@ -290,25 +308,29 @@ QTextCharFormat Html::ReadCharFormat(const QXmlStreamAttributes &attributes)
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)) {
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")));
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"))) {
} 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)) {
if (first_val.startsWith(QStringLiteral("rgba"),
Qt::CaseInsensitive)) {
QString vals_only = first_val;
vals_only.remove(QStringLiteral("rgba"));
vals_only.remove(QStringLiteral("("));
@@ -331,7 +353,8 @@ QTextCharFormat Html::ReadCharFormat(const QXmlStreamAttributes &attributes)
}
} else if (it.key() == QStringLiteral("letter-spacing")) {
if (first_val.contains(QChar('%'))) {
fmt.setFontLetterSpacing(first_val.chopped(1).toDouble());
fmt.setFontLetterSpacing(
first_val.chopped(1).toDouble());
}
} else if (it.key() == QStringLiteral("font-stretch")) {
if (first_val.contains(QChar('%'))) {
@@ -370,7 +393,9 @@ QTextBlockFormat Html::ReadBlockFormat(const QXmlStreamAttributes &attributes)
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);
block_fmt.setLineHeight(
first_val.chopped(1).toDouble(),
QTextBlockFormat::ProportionalHeight);
}
}
}
@@ -425,7 +450,8 @@ QMap<QString, QStringList> Html::GetCSSFromStyle(const QString &s)
values.append(current_str);
current_str.clear();
}
} else if (in_quote.isNull() && (current_char == QChar('\'') || current_char == QChar('"'))) {
} else if (in_quote.isNull() && (current_char == QChar('\'') ||
current_char == QChar('"'))) {
in_quote = current_char;
} else {
current_str.append(current_char);
+12 -7
View File
@@ -6,7 +6,8 @@
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
namespace olive {
namespace olive
{
/**
* @brief Functions for converting HTML to QTextDocument and vice versa
@@ -33,26 +34,30 @@ public:
private:
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)
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 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 QMap<QString, QStringList> GetCSSFromStyle(const QString &s);
static const QVector<QString> kBlockTags;
};
}
+2 -1
View File
@@ -2,7 +2,8 @@
#include <QMutex>
namespace olive {
namespace olive
{
uint64_t job_time_index = 0;
QMutex job_time_mutex;
+3 -4
View File
@@ -4,10 +4,10 @@
#include <QDebug>
#include <stdint.h>
namespace olive {
class JobTime
namespace olive
{
class JobTime {
public:
JobTime();
@@ -50,7 +50,6 @@ public:
private:
uint64_t value_;
};
}
+4 -3
View File
@@ -28,12 +28,13 @@ template<typename 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) {
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) {
template <typename T> T lerp(T a, T b, float t)
{
return (a * (1.0f - t)) + (b * t);
}
+17 -13
View File
@@ -31,7 +31,8 @@
#include "common/define.h"
namespace olive {
namespace olive
{
/**
* @brief MemoryPool base class
@@ -46,8 +47,7 @@ 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
{
class MemoryPool : public QObject {
Q_OBJECT
public:
/**
@@ -63,7 +63,8 @@ public:
clear_timer_ = new QTimer();
clear_timer_->setInterval(kMaxEmptyArenaLife);
clear_timer_->moveToThread(qApp->thread());
connect(clear_timer_, &QTimer::timeout, this, &MemoryPool::ClearEmptyArenas, Qt::DirectConnection);
connect(clear_timer_, &QTimer::timeout, this,
&MemoryPool::ClearEmptyArenas, Qt::DirectConnection);
QMetaObject::invokeMethod(clear_timer_, "start", Qt::QueuedConnection);
}
@@ -199,7 +200,6 @@ public:
int64_t timestamp_;
int64_t accessed_;
};
using ElementPtr = std::shared_ptr<Element>;
@@ -245,7 +245,8 @@ public:
// This buffer is available
available_.replace(i, false);
ElementPtr e = std::make_shared<Element>(this,
ElementPtr e = std::make_shared<Element>(
this,
reinterpret_cast<uint8_t *>(data_ + i * element_sz_));
lent_elements_.push_back(e.get());
@@ -262,7 +263,8 @@ public:
void Release(Element *e)
{
QMutexLocker locker(&lock_);
quintptr diff = reinterpret_cast<quintptr>(e->data()) - reinterpret_cast<quintptr>(data_);
quintptr diff = reinterpret_cast<quintptr>(e->data()) -
reinterpret_cast<quintptr>(data_);
int index = diff / element_sz_;
@@ -335,7 +337,6 @@ public:
std::list<Element *> lent_elements_;
qint64 empty_time_;
};
/**
@@ -369,13 +370,15 @@ public:
}
if (element_count_ <= 0) {
qCritical() << "Failed to create arena, element count was invalid:" << element_count_;
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?";
qCritical()
<< "Failed to create arena, allocation failed. Out of memory?";
delete a;
return nullptr;
}
@@ -411,12 +414,14 @@ private slots:
{
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) {
if (arena->GetUsageCount() == 0 &&
arena->GetTimeArenaWasMadeEmpty() <= min_time) {
qDebug() << "Removing an empty arena";
delete arena;
it = arenas_.erase(it);
@@ -425,7 +430,6 @@ private slots:
}
}
}
};
}
+2 -1
View File
@@ -20,7 +20,8 @@
#include "ocioutils.h"
namespace olive {
namespace olive
{
OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(PixelFormat format)
{
+3 -3
View File
@@ -26,10 +26,10 @@ namespace OCIO = OCIO_NAMESPACE;
#include "render/videoparams.h"
namespace olive {
class OCIOUtils
namespace olive
{
class OCIOUtils {
public:
static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(PixelFormat format);
};
+8 -12
View File
@@ -22,29 +22,25 @@
#include <QDebug>
namespace olive {
namespace olive
{
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());
buf->set_pixels(OIIO::ROI(), buf->spec().format, frame->const_data(),
OIIO::AutoStride, frame->linesize_bytes());
}
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)
+4 -3
View File
@@ -27,11 +27,13 @@
#include "codec/frame.h"
#include "render/videoparams.h"
namespace olive {
namespace olive
{
class OIIOUtils {
public:
static OIIO::TypeDesc::BASETYPE GetOIIOBaseTypeFromFormat(PixelFormat format)
static OIIO::TypeDesc::BASETYPE
GetOIIOBaseTypeFromFormat(PixelFormat format)
{
switch (format) {
case PixelFormat::U8:
@@ -57,7 +59,6 @@ public:
static PixelFormat GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type);
static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec);
};
}
+2 -1
View File
@@ -25,7 +25,8 @@
#include "common/define.h"
namespace olive {
namespace olive
{
uint32_t ceil_to_power_of_2(uint32_t v)
{
+25 -14
View File
@@ -22,9 +22,11 @@
#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);
#else
@@ -47,7 +49,9 @@ QFrame *QtUtils::CreateVerticalLine()
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);
@@ -85,7 +89,8 @@ QString QtUtils::GetFormattedDateTime(const QDateTime &dt)
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;
@@ -95,16 +100,17 @@ QStringList QtUtils::WordWrapString(const QString &s, const QFontMetrics &fm, in
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) {
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);
if (char_test.isSpace()
|| char_test == '-') {
if (QFontMetricsWidth(fm, this_line.left(j)) < bounding_width) {
if (char_test.isSpace() || char_test == '-') {
if (QFontMetricsWidth(fm, this_line.left(j)) <
bounding_width) {
if (!char_test.isSpace()) {
j++;
}
@@ -113,13 +119,16 @@ QStringList QtUtils::WordWrapString(const QString &s, const QFontMetrics &fm, in
list.append(chopped);
while (j < this_line.size() && this_line.at(j).isSpace()) {
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) {
} 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;
@@ -131,7 +140,8 @@ QStringList QtUtils::WordWrapString(const QString &s, const QFontMetrics &fm, in
list.append(this_line.left(hard_break));
this_line.remove(0, hard_break);
} else {
qWarning() << "Failed to find anywhere to wrap. Returning full line.";
qWarning()
<< "Failed to find anywhere to wrap. Returning full line.";
break;
}
}
@@ -145,7 +155,8 @@ QStringList QtUtils::WordWrapString(const QString &s, const QFontMetrics &fm, in
return list;
}
Qt::KeyboardModifiers QtUtils::FlipControlAndShiftModifiers(Qt::KeyboardModifiers e)
Qt::KeyboardModifiers
QtUtils::FlipControlAndShiftModifiers(Qt::KeyboardModifiers e)
{
if (e & Qt::ControlModifier & Qt::ShiftModifier) {
return e;
@@ -195,7 +206,8 @@ QColor QtUtils::toQColor(const core::Color &i)
return c;
}
namespace core {
namespace core
{
uint qHash(const core::rational &r, uint seed)
{
@@ -207,7 +219,6 @@ uint qHash(const core::TimeRange &r, uint seed)
return qHash(r.in(), seed) ^ qHash(r.out(), seed);
}
}
}
+13 -10
View File
@@ -29,7 +29,8 @@
#include <QFrame>
#include <QMessageBox>
namespace olive {
namespace olive
{
class QtUtils {
public:
@@ -46,21 +47,24 @@ public:
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 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);
template <typename T>
static T *GetParentOfType(const QObject *child)
template <typename T> static T *GetParentOfType(const QObject *child)
{
QObject *t = child->parent();
@@ -87,15 +91,14 @@ public:
/**
* @brief Convert a NodeParam value to a pointer of any kind
*/
template<class T>
static T* ValueToPtr(const QVariant &ptr)
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);
+1 -2
View File
@@ -21,8 +21,7 @@
#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);
}
+21 -19
View File
@@ -24,23 +24,23 @@
#include <QMessageBox>
#include <QRegularExpression>
namespace olive {
namespace olive
{
double GetFloatRatioFromUser(QWidget* parent,
const QString& title,
bool* ok_in)
double GetFloatRatioFromUser(QWidget *parent, const QString &title, bool *ok_in)
{
QString s;
forever {
forever
{
bool ok;
s = QInputDialog::getText(parent,
title,
QCoreApplication::translate("RatioDialog", "Enter custom ratio (e.g. \"4:3\", \"16/9\", etc.):"),
QLineEdit::Normal,
s,
&ok);
s = QInputDialog::getText(
parent, title,
QCoreApplication::translate(
"RatioDialog",
"Enter custom ratio (e.g. \"4:3\", \"16/9\", etc.):"),
QLineEdit::Normal, s, &ok);
if (!ok) {
// User cancelled dialog, do nothing
@@ -50,7 +50,8 @@ double GetFloatRatioFromUser(QWidget* parent,
return qSNaN();
}
QStringList ratio_components = s.split(QRegularExpression(QStringLiteral(":|;|\\/")));
QStringList ratio_components =
s.split(QRegularExpression(QStringLiteral(":|;|\\/")));
if (ratio_components.size() == 1) {
bool float_ok;
@@ -69,10 +70,7 @@ double GetFloatRatioFromUser(QWidget* parent,
double num = ratio_components.at(0).toDouble(&numer_ok);
double den = ratio_components.at(1).toDouble(&denom_ok);
if (numer_ok
&& denom_ok
&& num > 0
&& den > 0) {
if (numer_ok && denom_ok && num > 0 && den > 0) {
// Exit loop and set this ratio
if (ok_in) {
*ok_in = true;
@@ -81,10 +79,14 @@ double GetFloatRatioFromUser(QWidget* parent,
}
}
QMessageBox::warning(parent,
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),
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);
}
}
+3 -3
View File
@@ -23,10 +23,10 @@
#include <QInputDialog>
namespace olive {
namespace olive
{
double GetFloatRatioFromUser(QWidget* parent,
const QString& title,
double GetFloatRatioFromUser(QWidget *parent, const QString &title,
bool *ok_in);
}
+1 -4
View File
@@ -4,9 +4,7 @@
#include <QMap>
#include <QMutex>
template <typename K, typename V>
class ThreadSafeMap
{
template <typename K, typename V> class ThreadSafeMap {
public:
ThreadSafeMap() = default;
@@ -21,7 +19,6 @@ private:
QMutex mutex_;
QMap<K, V> map_;
};
#endif // THREADSAFEMAP_H
+4 -2
View File
@@ -6,9 +6,11 @@
#include "common/define.h"
namespace olive {
namespace olive
{
inline QString ToHex(quint64 t) {
inline QString ToHex(quint64 t)
{
return QStringLiteral("%1").arg(t, 0, 16);
}
+1 -2
View File
@@ -21,8 +21,7 @@
#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;
}
+5 -4
View File
@@ -23,15 +23,16 @@
#include "node/block/block.h"
#include "node/factory.h"
namespace olive {
namespace olive
{
bool XMLReadNextStartElement(QXmlStreamReader *reader, CancelAtom *cancel_atom)
{
QXmlStreamReader::TokenType token;
while ((token = reader->readNext()) != QXmlStreamReader::Invalid
&& token != QXmlStreamReader::EndDocument
&& (!cancel_atom || !cancel_atom->IsCancelled())) {
while ((token = reader->readNext()) != QXmlStreamReader::Invalid &&
token != QXmlStreamReader::EndDocument &&
(!cancel_atom || !cancel_atom->IsCancelled())) {
if (reader->isEndElement()) {
return false;
} else if (reader->isStartElement()) {
+4 -2
View File
@@ -27,7 +27,8 @@
#include "render/cancelatom.h"
#include "undo/undocommand.h"
namespace olive {
namespace olive
{
class Block;
class Node;
@@ -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);
}
+207 -99
View File
@@ -37,7 +37,8 @@
#include "ui/style/style.h"
#include "window/mainwindow/mainwindow.h"
namespace olive {
namespace olive
{
Config Config::current_config_;
@@ -46,14 +47,16 @@ Config::Config()
SetDefaults();
}
void Config::SetEntryInternal(const QString &key, NodeValue::Type type, const QVariant &data)
void Config::SetEntryInternal(const QString &key, NodeValue::Type type,
const QVariant &data)
{
config_map_[key] = { type, data };
}
QString Config::GetConfigFilePath()
{
return QDir(FileFunctions::GetConfigurationLocation()).filePath(QStringLiteral("config.xml"));
return QDir(FileFunctions::GetConfigurationLocation())
.filePath(QStringLiteral("config.xml"));
}
Config &Config::Current()
@@ -64,106 +67,190 @@ Config &Config::Current()
void Config::SetDefaults()
{
config_map_.clear();
SetEntryInternal(QStringLiteral("Style"), NodeValue::kText, StyleManager::kDefaultStyle);
SetEntryInternal(QStringLiteral("TimecodeDisplay"), NodeValue::kInt, Timecode::kTimecodeDropFrame);
SetEntryInternal(QStringLiteral("DefaultStillLength"), NodeValue::kRational, QVariant::fromValue(rational(2)));
SetEntryInternal(QStringLiteral("Style"), NodeValue::kText,
StyleManager::kDefaultStyle);
SetEntryInternal(QStringLiteral("TimecodeDisplay"), NodeValue::kInt,
Timecode::kTimecodeDropFrame);
SetEntryInternal(QStringLiteral("DefaultStillLength"), NodeValue::kRational,
QVariant::fromValue(rational(2)));
SetEntryInternal(QStringLiteral("HoverFocus"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("AudioScrubbing"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("AutorecoveryEnabled"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("AutorecoveryInterval"), NodeValue::kInt, 1);
SetEntryInternal(QStringLiteral("AutorecoveryMaximum"), NodeValue::kInt, 20);
SetEntryInternal(QStringLiteral("DiskCacheSaveInterval"), NodeValue::kInt, 10000);
SetEntryInternal(QStringLiteral("AudioScrubbing"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("AutorecoveryEnabled"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("AutorecoveryInterval"), NodeValue::kInt,
1);
SetEntryInternal(QStringLiteral("AutorecoveryMaximum"), NodeValue::kInt,
20);
SetEntryInternal(QStringLiteral("DiskCacheSaveInterval"), NodeValue::kInt,
10000);
SetEntryInternal(QStringLiteral("Language"), NodeValue::kText, QString());
SetEntryInternal(QStringLiteral("ScrollZooms"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("EnableSeekToImport"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("EditToolAlsoSeeks"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("EditToolSelectsLinks"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("EnableDragFilesToTimeline"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("InvertTimelineScrollAxes"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("SelectAlsoSeeks"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("EnableSeekToImport"), NodeValue::kBoolean,
false);
SetEntryInternal(QStringLiteral("EditToolAlsoSeeks"), NodeValue::kBoolean,
false);
SetEntryInternal(QStringLiteral("EditToolSelectsLinks"),
NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("EnableDragFilesToTimeline"),
NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("InvertTimelineScrollAxes"),
NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("SelectAlsoSeeks"), NodeValue::kBoolean,
false);
SetEntryInternal(QStringLiteral("PasteSeeks"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("SeekAlsoSelects"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("SetNameWithMarker"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("AutoSeekToBeginning"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("DropFileOnMediaToReplace"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("AddDefaultEffectsToClips"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("AutoscaleByDefault"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("Autoscroll"), NodeValue::kInt, AutoScroll::kPage);
SetEntryInternal(QStringLiteral("AutoSelectDivider"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("SetNameWithMarker"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("RectifiedWaveforms"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("DropWithoutSequenceBehavior"), NodeValue::kInt, ImportTool::kDWSAsk);
SetEntryInternal(QStringLiteral("SeekAlsoSelects"), NodeValue::kBoolean,
false);
SetEntryInternal(QStringLiteral("SetNameWithMarker"), NodeValue::kBoolean,
false);
SetEntryInternal(QStringLiteral("AutoSeekToBeginning"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("DropFileOnMediaToReplace"),
NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("AddDefaultEffectsToClips"),
NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("AutoscaleByDefault"), NodeValue::kBoolean,
false);
SetEntryInternal(QStringLiteral("Autoscroll"), NodeValue::kInt,
AutoScroll::kPage);
SetEntryInternal(QStringLiteral("AutoSelectDivider"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("SetNameWithMarker"), NodeValue::kBoolean,
false);
SetEntryInternal(QStringLiteral("RectifiedWaveforms"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("DropWithoutSequenceBehavior"),
NodeValue::kInt, ImportTool::kDWSAsk);
SetEntryInternal(QStringLiteral("Loop"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("SplitClipsCopyNodes"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("SplitClipsCopyNodes"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("UseGradients"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("AutoMergeTracks"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("UseSliderLadders"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("ShowWelcomeDialog"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("ShowClipWhileDragging"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("StopPlaybackOnLastFrame"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("UseLegacyColorInInputTab"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("ReassocLinToNonLin"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("PreviewNonFloatDontAskAgain"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("AutoMergeTracks"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("UseSliderLadders"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("ShowWelcomeDialog"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("ShowClipWhileDragging"),
NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("StopPlaybackOnLastFrame"),
NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("UseLegacyColorInInputTab"),
NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("ReassocLinToNonLin"), NodeValue::kBoolean,
false);
SetEntryInternal(QStringLiteral("PreviewNonFloatDontAskAgain"),
NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("UseGLFinish"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("TimelineThumbnailMode"), NodeValue::kInt, Timeline::kThumbnailInOut);
SetEntryInternal(QStringLiteral("TimelineWaveformMode"), NodeValue::kInt, Timeline::kWaveformsEnabled);
SetEntryInternal(QStringLiteral("TimelineThumbnailMode"), NodeValue::kInt,
Timeline::kThumbnailInOut);
SetEntryInternal(QStringLiteral("TimelineWaveformMode"), NodeValue::kInt,
Timeline::kWaveformsEnabled);
SetEntryInternal(QStringLiteral("DefaultVideoTransition"), NodeValue::kText, QStringLiteral("org.olivevideoeditor.Olive.crossdissolve"));
SetEntryInternal(QStringLiteral("DefaultAudioTransition"), NodeValue::kText, QStringLiteral("org.olivevideoeditor.Olive.crossdissolve"));
SetEntryInternal(QStringLiteral("DefaultTransitionLength"), NodeValue::kRational, QVariant::fromValue(rational(1)));
SetEntryInternal(
QStringLiteral("DefaultVideoTransition"), NodeValue::kText,
QStringLiteral("org.olivevideoeditor.Olive.crossdissolve"));
SetEntryInternal(
QStringLiteral("DefaultAudioTransition"), NodeValue::kText,
QStringLiteral("org.olivevideoeditor.Olive.crossdissolve"));
SetEntryInternal(QStringLiteral("DefaultTransitionLength"),
NodeValue::kRational, QVariant::fromValue(rational(1)));
SetEntryInternal(QStringLiteral("DefaultSubtitleSize"), NodeValue::kInt, 48);
SetEntryInternal(QStringLiteral("DefaultSubtitleFamily"), NodeValue::kText, QString());
SetEntryInternal(QStringLiteral("DefaultSubtitleWeight"), NodeValue::kInt, QFont::Bold);
SetEntryInternal(QStringLiteral("AntialiasSubtitles"), NodeValue::kBoolean, true);
SetEntryInternal(QStringLiteral("DefaultSubtitleSize"), NodeValue::kInt,
48);
SetEntryInternal(QStringLiteral("DefaultSubtitleFamily"), NodeValue::kText,
QString());
SetEntryInternal(QStringLiteral("DefaultSubtitleWeight"), NodeValue::kInt,
QFont::Bold);
SetEntryInternal(QStringLiteral("AntialiasSubtitles"), NodeValue::kBoolean,
true);
SetEntryInternal(QStringLiteral("AutoCacheDelay"), NodeValue::kInt, 1000);
SetEntryInternal(QStringLiteral("CatColor0"), NodeValue::kInt, ColorCoding::kRed);
SetEntryInternal(QStringLiteral("CatColor1"), NodeValue::kInt, ColorCoding::kMaroon);
SetEntryInternal(QStringLiteral("CatColor2"), NodeValue::kInt, ColorCoding::kOrange);
SetEntryInternal(QStringLiteral("CatColor3"), NodeValue::kInt, ColorCoding::kBrown);
SetEntryInternal(QStringLiteral("CatColor4"), NodeValue::kInt, ColorCoding::kYellow);
SetEntryInternal(QStringLiteral("CatColor5"), NodeValue::kInt, ColorCoding::kOlive);
SetEntryInternal(QStringLiteral("CatColor6"), NodeValue::kInt, ColorCoding::kLime);
SetEntryInternal(QStringLiteral("CatColor7"), NodeValue::kInt, ColorCoding::kGreen);
SetEntryInternal(QStringLiteral("CatColor8"), NodeValue::kInt, ColorCoding::kCyan);
SetEntryInternal(QStringLiteral("CatColor9"), NodeValue::kInt, ColorCoding::kTeal);
SetEntryInternal(QStringLiteral("CatColor10"), NodeValue::kInt, ColorCoding::kBlue);
SetEntryInternal(QStringLiteral("CatColor11"), NodeValue::kInt, ColorCoding::kNavy);
SetEntryInternal(QStringLiteral("CatColor0"), NodeValue::kInt,
ColorCoding::kRed);
SetEntryInternal(QStringLiteral("CatColor1"), NodeValue::kInt,
ColorCoding::kMaroon);
SetEntryInternal(QStringLiteral("CatColor2"), NodeValue::kInt,
ColorCoding::kOrange);
SetEntryInternal(QStringLiteral("CatColor3"), NodeValue::kInt,
ColorCoding::kBrown);
SetEntryInternal(QStringLiteral("CatColor4"), NodeValue::kInt,
ColorCoding::kYellow);
SetEntryInternal(QStringLiteral("CatColor5"), NodeValue::kInt,
ColorCoding::kOlive);
SetEntryInternal(QStringLiteral("CatColor6"), NodeValue::kInt,
ColorCoding::kLime);
SetEntryInternal(QStringLiteral("CatColor7"), NodeValue::kInt,
ColorCoding::kGreen);
SetEntryInternal(QStringLiteral("CatColor8"), NodeValue::kInt,
ColorCoding::kCyan);
SetEntryInternal(QStringLiteral("CatColor9"), NodeValue::kInt,
ColorCoding::kTeal);
SetEntryInternal(QStringLiteral("CatColor10"), NodeValue::kInt,
ColorCoding::kBlue);
SetEntryInternal(QStringLiteral("CatColor11"), NodeValue::kInt,
ColorCoding::kNavy);
SetEntryInternal(QStringLiteral("AudioOutput"), NodeValue::kText, QString());
SetEntryInternal(QStringLiteral("AudioOutput"), NodeValue::kText,
QString());
SetEntryInternal(QStringLiteral("AudioInput"), NodeValue::kText, QString());
SetEntryInternal(QStringLiteral("AudioOutputSampleRate"), NodeValue::kInt, 48000);
SetEntryInternal(QStringLiteral("AudioOutputChannelLayout"), NodeValue::kInt, AV_CH_LAYOUT_STEREO);
SetEntryInternal(QStringLiteral("AudioOutputSampleFormat"), NodeValue::kText, QString::fromStdString(SampleFormat(SampleFormat::S16).to_string()));
SetEntryInternal(QStringLiteral("AudioOutputSampleRate"), NodeValue::kInt,
48000);
SetEntryInternal(QStringLiteral("AudioOutputChannelLayout"),
NodeValue::kInt, AV_CH_LAYOUT_STEREO);
SetEntryInternal(
QStringLiteral("AudioOutputSampleFormat"), NodeValue::kText,
QString::fromStdString(SampleFormat(SampleFormat::S16).to_string()));
SetEntryInternal(QStringLiteral("AudioRecordingFormat"), NodeValue::kInt, ExportFormat::kFormatWAV);
SetEntryInternal(QStringLiteral("AudioRecordingCodec"), NodeValue::kInt, ExportCodec::kCodecPCM);
SetEntryInternal(QStringLiteral("AudioRecordingSampleRate"), NodeValue::kInt, 48000);
SetEntryInternal(QStringLiteral("AudioRecordingChannelLayout"), NodeValue::kInt, AV_CH_LAYOUT_STEREO);
SetEntryInternal(QStringLiteral("AudioRecordingSampleFormat"), NodeValue::kText, QString::fromStdString(SampleFormat(SampleFormat::S16).to_string()));
SetEntryInternal(QStringLiteral("AudioRecordingBitRate"), NodeValue::kInt, 320);
SetEntryInternal(QStringLiteral("AudioRecordingFormat"), NodeValue::kInt,
ExportFormat::kFormatWAV);
SetEntryInternal(QStringLiteral("AudioRecordingCodec"), NodeValue::kInt,
ExportCodec::kCodecPCM);
SetEntryInternal(QStringLiteral("AudioRecordingSampleRate"),
NodeValue::kInt, 48000);
SetEntryInternal(QStringLiteral("AudioRecordingChannelLayout"),
NodeValue::kInt, AV_CH_LAYOUT_STEREO);
SetEntryInternal(
QStringLiteral("AudioRecordingSampleFormat"), NodeValue::kText,
QString::fromStdString(SampleFormat(SampleFormat::S16).to_string()));
SetEntryInternal(QStringLiteral("AudioRecordingBitRate"), NodeValue::kInt,
320);
SetEntryInternal(QStringLiteral("DiskCacheBehind"), NodeValue::kRational, QVariant::fromValue(rational(0)));
SetEntryInternal(QStringLiteral("DiskCacheAhead"), NodeValue::kRational, QVariant::fromValue(rational(60)));
SetEntryInternal(QStringLiteral("DiskCacheBehind"), NodeValue::kRational,
QVariant::fromValue(rational(0)));
SetEntryInternal(QStringLiteral("DiskCacheAhead"), NodeValue::kRational,
QVariant::fromValue(rational(60)));
SetEntryInternal(QStringLiteral("DefaultSequenceWidth"), NodeValue::kInt, 1920);
SetEntryInternal(QStringLiteral("DefaultSequenceHeight"), NodeValue::kInt, 1080);
SetEntryInternal(QStringLiteral("DefaultSequencePixelAspect"), NodeValue::kRational, QVariant::fromValue(rational(1)));
SetEntryInternal(QStringLiteral("DefaultSequenceFrameRate"), NodeValue::kRational, QVariant::fromValue(rational(1001, 30000)));
SetEntryInternal(QStringLiteral("DefaultSequenceInterlacing"), NodeValue::kInt, VideoParams::kInterlaceNone);
SetEntryInternal(QStringLiteral("DefaultSequenceAutoCache2"), NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("DefaultSequenceAudioFrequency"), NodeValue::kInt, 48000);
SetEntryInternal(QStringLiteral("DefaultSequenceAudioLayout"), NodeValue::kInt, QVariant::fromValue(static_cast<int64_t>(AV_CH_LAYOUT_STEREO)));
SetEntryInternal(QStringLiteral("DefaultSequenceWidth"), NodeValue::kInt,
1920);
SetEntryInternal(QStringLiteral("DefaultSequenceHeight"), NodeValue::kInt,
1080);
SetEntryInternal(QStringLiteral("DefaultSequencePixelAspect"),
NodeValue::kRational, QVariant::fromValue(rational(1)));
SetEntryInternal(QStringLiteral("DefaultSequenceFrameRate"),
NodeValue::kRational,
QVariant::fromValue(rational(1001, 30000)));
SetEntryInternal(QStringLiteral("DefaultSequenceInterlacing"),
NodeValue::kInt, VideoParams::kInterlaceNone);
SetEntryInternal(QStringLiteral("DefaultSequenceAutoCache2"),
NodeValue::kBoolean, false);
SetEntryInternal(QStringLiteral("DefaultSequenceAudioFrequency"),
NodeValue::kInt, 48000);
SetEntryInternal(
QStringLiteral("DefaultSequenceAudioLayout"), NodeValue::kInt,
QVariant::fromValue(static_cast<int64_t>(AV_CH_LAYOUT_STEREO)));
// Online/offline settings
SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeValue::kInt, PixelFormat::F32);
SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeValue::kInt, PixelFormat::F16);
SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeValue::kInt,
PixelFormat::F32);
SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeValue::kInt,
PixelFormat::F16);
SetEntryInternal(QStringLiteral("MarkerColor"), NodeValue::kInt, ColorCoding::kLime);
SetEntryInternal(QStringLiteral("MarkerColor"), NodeValue::kInt,
ColorCoding::kLime);
}
void Config::Load()
@@ -175,7 +262,8 @@ void Config::Load()
}
if (!config_file.open(QFile::ReadOnly)) {
qWarning() << "Failed to load application settings. This session will use defaults.";
qWarning()
<< "Failed to load application settings. This session will use defaults.";
return;
}
@@ -196,22 +284,26 @@ void Config::Load()
config_version = value;
if (!value.contains(".")) {
qDebug() << "CONFIG: This is a 0.1.x config file, upconvert";
qDebug()
<< "CONFIG: This is a 0.1.x config file, upconvert";
}
} else if (key == QStringLiteral("DefaultSequenceFrameRate") && !config_version.contains('.')) {
} else if (key == QStringLiteral("DefaultSequenceFrameRate") &&
!config_version.contains('.')) {
// 0.1.x stored this value as a float while we now use rationals, we'll use a heuristic to find the closest
// supported rational
qDebug() << " CONFIG: Finding closest match to" << value;
double config_fr = value.toDouble();
const QVector<rational>& supported_frame_rates = VideoParams::kSupportedFrameRates;
const QVector<rational> &supported_frame_rates =
VideoParams::kSupportedFrameRates;
rational match = supported_frame_rates.first();
double match_diff = qAbs(match.toDouble() - config_fr);
for (int i = 1; i < supported_frame_rates.size(); i++) {
double diff = qAbs(supported_frame_rates.at(i).toDouble() - config_fr);
double diff = qAbs(
supported_frame_rates.at(i).toDouble() - config_fr);
if (diff < match_diff) {
match = supported_frame_rates.at(i);
@@ -219,11 +311,13 @@ void Config::Load()
}
}
qDebug() << " CONFIG: Closest match was" << match.toDouble();
qDebug()
<< " CONFIG: Closest match was" << match.toDouble();
current_config_[key] = QVariant::fromValue(match.flipped());
} else {
current_config_[key] = NodeValue::StringToValue(current_config_.GetConfigEntryType(key), value, false);
current_config_[key] = NodeValue::StringToValue(
current_config_.GetConfigEntryType(key), value, false);
}
}
@@ -234,10 +328,14 @@ void Config::Load()
}
if (reader.hasError()) {
QMessageBox::critical(Core::instance()->main_window(),
QMessageBox::critical(
Core::instance()->main_window(),
QCoreApplication::translate("Config", "Error loading settings"),
QCoreApplication::translate("Config", "Failed to load application settings. This session will "
"use defaults.\n\n%1").arg(reader.errorString()),
QCoreApplication::translate(
"Config",
"Failed to load application settings. This session will "
"use defaults.\n\n%1")
.arg(reader.errorString()),
QMessageBox::Ok);
current_config_.SetDefaults();
}
@@ -248,14 +346,18 @@ void Config::Load()
void Config::Save()
{
QString real_filename = GetConfigFilePath();
QString temp_filename = FileFunctions::GetSafeTemporaryFilename(real_filename);
QString temp_filename =
FileFunctions::GetSafeTemporaryFilename(real_filename);
QFile config_file(temp_filename);
if (!config_file.open(QFile::WriteOnly)) {
QMessageBox::critical(Core::instance()->main_window(),
QMessageBox::critical(
Core::instance()->main_window(),
QCoreApplication::translate("Config", "Error saving settings"),
QCoreApplication::translate("Config", "Failed to save application settings. The application "
QCoreApplication::translate(
"Config",
"Failed to save application settings. The application "
"may lack write permissions for this location."),
QMessageBox::Ok);
return;
@@ -269,16 +371,19 @@ void Config::Save()
writer.writeStartElement("Configuration");
// Anything after the hyphen is considered "unimportant" information
writer.writeTextElement("Version", QCoreApplication::applicationVersion().split('-').first());
writer.writeTextElement(
"Version", QCoreApplication::applicationVersion().split('-').first());
QMapIterator<QString, ConfigEntry> iterator(current_config_.config_map_);
while (iterator.hasNext()) {
iterator.next();
QString value = NodeValue::ValueToString(iterator.value().type, iterator.value().data, false);
QString value = NodeValue::ValueToString(iterator.value().type,
iterator.value().data, false);
if (iterator.value().type == NodeValue::kNone) {
qWarning() << "Config key" << iterator.key() << "had null type and was discarded";
qWarning() << "Config key" << iterator.key()
<< "had null type and was discarded";
} else {
writer.writeTextElement(iterator.key(), value);
}
@@ -290,8 +395,11 @@ void Config::Save()
config_file.close();
if (!FileFunctions::RenameFileAllowOverwrite(temp_filename, real_filename)) {
qWarning() << QStringLiteral("Failed to overwrite \"%1\". Config has been saved as \"%2\" instead.")
if (!FileFunctions::RenameFileAllowOverwrite(temp_filename,
real_filename)) {
qWarning()
<< QStringLiteral(
"Failed to overwrite \"%1\". Config has been saved as \"%2\" instead.")
.arg(real_filename, temp_filename);
}
}
+4 -2
View File
@@ -27,7 +27,8 @@
#include "node/value.h"
namespace olive {
namespace olive
{
#define OLIVE_CONFIG(x) Config::Current()[QStringLiteral(x)]
#define OLIVE_CONFIG_STR(x) Config::Current()[x]
@@ -56,7 +57,8 @@ private:
QVariant data;
};
void SetEntryInternal(const QString& key, NodeValue::Type type, const QVariant& data);
void SetEntryInternal(const QString &key, NodeValue::Type type,
const QVariant &data);
QMap<QString, ConfigEntry> config_map_;
+231 -145
View File
@@ -78,20 +78,21 @@
#include "window/mainwindow/mainstatusbar.h"
#include "window/mainwindow/mainwindow.h"
namespace olive {
namespace olive
{
Core *Core::instance_ = nullptr;
Core::Core(const CoreParams& params) :
main_window_(nullptr),
open_project_(nullptr),
tool_(Tool::kPointer),
addable_object_(Tool::kAddableEmpty),
snapping_(true),
core_params_(params),
magic_(false),
pixel_sampling_users_(0),
shown_cache_full_warning_(false)
Core::Core(const CoreParams &params)
: main_window_(nullptr)
, open_project_(nullptr)
, tool_(Tool::kPointer)
, addable_object_(Tool::kAddableEmpty)
, snapping_(true)
, core_params_(params)
, magic_(false)
, pixel_sampling_users_(0)
, shown_cache_full_warning_(false)
{
// Store reference to this object, making the assumption that Core will only ever be made in
// main(). This will obviously break if not.
@@ -169,7 +170,8 @@ void Core::Start()
StartGUI(core_params_.fullscreen());
// If we have a startup
QMetaObject::invokeMethod(this, "OpenStartupProject", Qt::QueuedConnection);
QMetaObject::invokeMethod(this, "OpenStartupProject",
Qt::QueuedConnection);
break;
case CoreParams::kHeadlessExport:
qInfo() << "Headless export is not fully implemented yet";
@@ -182,12 +184,11 @@ void Core::Start()
// Manual crash triggering
if (core_params_.crash_on_startup()) {
const int interval = 5000;
qInfo() << "Manual crash was triggered. Application will crash in" << interval << "ms";
qInfo() << "Manual crash was triggered. Application will crash in"
<< interval << "ms";
QTimer *crash_timer = new QTimer(this);
crash_timer->setInterval(interval);
connect(crash_timer, &QTimer::timeout, this, []{
abort();
});
connect(crash_timer, &QTimer::timeout, this, [] { abort(); });
crash_timer->start();
}
}
@@ -238,7 +239,8 @@ UndoStack *Core::undo_stack()
void Core::ImportFiles(const QStringList &urls, Folder *parent)
{
if (urls.isEmpty()) {
QMessageBox::critical(main_window_, tr("Import error"), tr("Nothing to import"));
QMessageBox::critical(main_window_, tr("Import error"),
tr("Nothing to import"));
return;
}
@@ -250,9 +252,11 @@ void Core::ImportFiles(const QStringList &urls, Folder* parent)
return;
}
TaskDialog* task_dialog = new TaskDialog(pim, tr("Importing..."), main_window());
TaskDialog *task_dialog =
new TaskDialog(pim, tr("Importing..."), main_window());
connect(task_dialog, &TaskDialog::TaskSucceeded, this, &Core::ImportTaskComplete);
connect(task_dialog, &TaskDialog::TaskSucceeded, this,
&Core::ImportTaskComplete);
task_dialog->open();
}
@@ -333,19 +337,22 @@ void Core::DialogAboutShow()
void Core::DialogImportShow()
{
// Open dialog for user to select files
QStringList files = QFileDialog::getOpenFileNames(main_window_,
tr("Import footage..."));
QStringList files =
QFileDialog::getOpenFileNames(main_window_, tr("Import footage..."));
// Check if the user actually selected files to import
if (!files.isEmpty()) {
// Locate the most recently focused Project panel (assume that's the panel the user wants to import into)
ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused<ProjectPanel>();
ProjectPanel *active_project_panel =
PanelManager::instance()->MostRecentlyFocused<ProjectPanel>();
Project *active_project;
if (active_project_panel == nullptr // Check that we found a Project panel
|| (active_project = active_project_panel->project()) == nullptr) { // and that we could find an active Project
QMessageBox::critical(main_window_, tr("Failed to import footage"), tr("Failed to find active Project panel"));
if (active_project_panel ==
nullptr // Check that we found a Project panel
|| (active_project = active_project_panel->project()) ==
nullptr) { // and that we could find an active Project
QMessageBox::critical(main_window_, tr("Failed to import footage"),
tr("Failed to find active Project panel"));
return;
}
@@ -370,8 +377,8 @@ void Core::DialogProjectPropertiesShow()
ProjectPropertiesDialog ppd(proj, main_window_);
ppd.exec();
} else {
QMessageBox::critical(main_window_,
tr("No Active Project"),
QMessageBox::critical(
main_window_, tr("No Active Project"),
tr("No project is currently open to set the properties for"),
QMessageBox::Ok);
}
@@ -385,7 +392,8 @@ void Core::DialogExportShow()
}
#ifdef USE_OTIO
bool Core::DialogImportOTIOShow(const QList<Sequence*>& sequences) {
bool Core::DialogImportOTIOShow(const QList<Sequence *> &sequences)
{
Project *active_project = GetActiveProject();
OTIOPropertiesDialog opd(sequences, active_project);
return opd.exec() == QDialog::Accepted;
@@ -395,12 +403,15 @@ bool Core::DialogImportOTIOShow(const QList<Sequence*>& sequences) {
void Core::CreateNewFolder()
{
// Locate the most recently focused Project panel (assume that's the panel the user wants to import into)
ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused<ProjectPanel>();
ProjectPanel *active_project_panel =
PanelManager::instance()->MostRecentlyFocused<ProjectPanel>();
Project *active_project;
if (active_project_panel == nullptr // Check that we found a Project panel
|| (active_project = active_project_panel->project()) == nullptr) { // and that we could find an active Project
QMessageBox::critical(main_window_, tr("Failed to create new folder"), tr("Failed to find active project"));
|| (active_project = active_project_panel->project()) ==
nullptr) { // and that we could find an active Project
QMessageBox::critical(main_window_, tr("Failed to create new folder"),
tr("Failed to find active project"));
return;
}
@@ -430,7 +441,8 @@ void Core::CreateNewSequence()
Project *active_project = GetActiveProject();
if (!active_project) {
QMessageBox::critical(main_window_, tr("Failed to create new sequence"), tr("Failed to find active project"));
QMessageBox::critical(main_window_, tr("Failed to create new sequence"),
tr("Failed to find active project"));
return;
}
@@ -444,25 +456,25 @@ void Core::CreateNewSequence()
sd.SetUndoable(false);
if (sd.exec() == QDialog::Accepted) {
// Create an undoable command
MultiUndoCommand *command = new MultiUndoCommand();
command->add_child(new NodeAddCommand(active_project, new_sequence));
command->add_child(new FolderAddChild(GetSelectedFolderInActiveProject(), new_sequence));
command->add_child(new NodeSetPositionCommand(new_sequence, new_sequence, Node::Position()));
command->add_child(new FolderAddChild(
GetSelectedFolderInActiveProject(), new_sequence));
command->add_child(new NodeSetPositionCommand(
new_sequence, new_sequence, Node::Position()));
command->add_child(new OpenSequenceCommand(new_sequence));
// Create and connect default nodes to new sequence
new_sequence->add_default_nodes(command);
Core::instance()->undo_stack()->push(command, tr("Created New Sequence"));
Core::instance()->undo_stack()->push(command,
tr("Created New Sequence"));
} else {
// If the dialog was accepted, ownership goes to the AddItemCommand. But if we get here, just delete
delete new_sequence;
}
}
@@ -509,7 +521,8 @@ bool Core::AddOpenProjectFromTask(Task *task, bool add_to_recents)
void Core::SetActiveProject(Project *p)
{
if (open_project_) {
disconnect(open_project_, &Project::ModifiedChanged, this, &Core::ProjectWasModified);
disconnect(open_project_, &Project::ModifiedChanged, this,
&Core::ProjectWasModified);
}
open_project_ = p;
@@ -517,7 +530,8 @@ void Core::SetActiveProject(Project *p)
main_window_->SetProject(p);
if (open_project_) {
connect(open_project_, &Project::ModifiedChanged, this, &Core::ProjectWasModified);
connect(open_project_, &Project::ModifiedChanged, this,
&Core::ProjectWasModified);
}
}
@@ -534,7 +548,8 @@ void Core::ImportTaskComplete(Task* task)
for (int i = 0; i < f->GetVideoStreamCount(); i++) {
const VideoParams &vs = f->GetVideoParams(i);
if (!(vs.video_type() == VideoParams::kVideoTypeStill && vs.enabled() == (i == 0))) {
if (!(vs.video_type() == VideoParams::kVideoTypeStill &&
vs.enabled() == (i == 0))) {
all_stills = false;
}
}
@@ -544,11 +559,15 @@ void Core::ImportTaskComplete(Task* task)
d.setIcon(QMessageBox::Question);
d.setWindowTitle(tr("Multi-Layer Image"));
d.setText(tr("The file '%1' has multiple layers. Would you like these layers to be "
"separated across multiple tracks or merged into a single image?").arg(f->filename()));
d.setText(
tr("The file '%1' has multiple layers. Would you like these layers to be "
"separated across multiple tracks or merged into a single image?")
.arg(f->filename()));
auto multi_btn = d.addButton(tr("Multiple Layers"), QMessageBox::YesRole);
auto single_btn = d.addButton(tr("Single Layer"), QMessageBox::NoRole);
auto multi_btn =
d.addButton(tr("Multiple Layers"), QMessageBox::YesRole);
auto single_btn =
d.addButton(tr("Single Layer"), QMessageBox::NoRole);
auto cancel_btn = d.addButton(QMessageBox::Cancel);
d.exec();
@@ -571,11 +590,14 @@ void Core::ImportTaskComplete(Task* task)
}
if (import_task->HasInvalidFiles()) {
ProjectImportErrorDialog d(import_task->GetInvalidFiles(), main_window_);
ProjectImportErrorDialog d(import_task->GetInvalidFiles(),
main_window_);
d.exec();
}
undo_stack_.push(command, tr("Imported %1 File(s)").arg(import_task->GetImportedFootage().size()));
undo_stack_.push(
command,
tr("Imported %1 File(s)").arg(import_task->GetImportedFootage().size()));
main_window_->SelectFootage(import_task->GetImportedFootage());
}
@@ -587,7 +609,8 @@ bool Core::ConfirmImageSequence(const QString& filename)
mb.setIcon(QMessageBox::Question);
mb.setWindowTitle(tr("Possible image sequence detected"));
mb.setText(tr("The file '%1' looks like it might be part of an image "
"sequence. Would you like to import it as such?").arg(filename));
"sequence. Would you like to import it as such?")
.arg(filename));
mb.addButton(QMessageBox::Yes);
mb.addButton(QMessageBox::No);
@@ -605,7 +628,8 @@ bool Core::StartHeadlessExport()
const QString &startup_project = core_params_.startup_project();
if (startup_project.isEmpty()) {
qCritical().noquote() << tr("You must specify a project file to export");
qCritical().noquote()
<< tr("You must specify a project file to export");
return false;
}
@@ -689,14 +713,15 @@ bool Core::StartHeadlessExport()
void Core::OpenStartupProject()
{
const QString &startup_project = core_params_.startup_project();
bool startup_project_exists = !startup_project.isEmpty() && QFileInfo::exists(startup_project);
bool startup_project_exists = !startup_project.isEmpty() &&
QFileInfo::exists(startup_project);
// Load startup project
if (!startup_project_exists && !startup_project.isEmpty()) {
QMessageBox::warning(main_window_,
tr("Failed to open startup file"),
QMessageBox::warning(main_window_, tr("Failed to open startup file"),
tr("The project \"%1\" doesn't exist. "
"A new project will be started instead.").arg(startup_project),
"A new project will be started instead.")
.arg(startup_project),
QMessageBox::Ok);
}
@@ -712,7 +737,8 @@ void Core::OpenStartupProject()
void Core::AddRecoveryProjectFromTask(Task *task)
{
if (AddOpenProjectFromTask(task, false)) {
ProjectLoadBaseTask* load_task = static_cast<ProjectLoadBaseTask*>(task);
ProjectLoadBaseTask *load_task =
static_cast<ProjectLoadBaseTask *>(task);
Project *project = load_task->GetLoadedProject();
@@ -747,9 +773,7 @@ void Core::StartGUI(bool full_screen)
DiskManager::CreateInstance();
// Connect the PanelFocusManager to the application's focus change signal
connect(qApp,
&QApplication::focusChanged,
PanelManager::instance(),
connect(qApp, &QApplication::focusChanged, PanelManager::instance(),
&PanelManager::FocusChanged);
// Set KDDockWidgets flags
@@ -774,12 +798,14 @@ void Core::StartGUI(bool full_screen)
#ifdef Q_OS_WINDOWS
// Workaround for Qt bug where menus don't appear in full screen mode
// See: https://doc.qt.io/qt-5/windows-issues.html
QWindowsWindowFunctions::setHasBorderInFullScreen(main_window_->windowHandle(), true);
QWindowsWindowFunctions::setHasBorderInFullScreen(
main_window_->windowHandle(), true);
#endif
// Start autorecovery timer using the config value as its interval
SetAutorecoveryInterval(OLIVE_CONFIG("AutorecoveryInterval").toInt());
connect(&autorecovery_timer_, &QTimer::timeout, this, &Core::SaveAutorecovery);
connect(&autorecovery_timer_, &QTimer::timeout, this,
&Core::SaveAutorecovery);
autorecovery_timer_.start();
// Load recently opened projects list
@@ -802,24 +828,28 @@ void Core::SaveProjectInternal(const QString& override_filename)
// Create save manager
Task *psm;
if (open_project_->filename().endsWith(QStringLiteral(".otio"), Qt::CaseInsensitive)) {
if (open_project_->filename().endsWith(QStringLiteral(".otio"),
Qt::CaseInsensitive)) {
#ifdef USE_OTIO
psm = new SaveOTIOTask(open_project_);
#else
QMessageBox::critical(main_window_,
tr("Missing OpenTimelineIO Libraries"),
QMessageBox::critical(
main_window_, tr("Missing OpenTimelineIO Libraries"),
tr("This build was compiled without OpenTimelineIO and therefore "
"cannot open OpenTimelineIO files."));
return;
#endif
} else {
bool use_compression = !open_project_->filename().endsWith(QStringLiteral(".ovexml"), Qt::CaseInsensitive);
bool use_compression = !open_project_->filename().endsWith(
QStringLiteral(".ovexml"), Qt::CaseInsensitive);
psm = new ProjectSaveTask(open_project_, use_compression);
static_cast<ProjectSaveTask*>(psm)->SetLayout(main_window_->SaveLayout());
static_cast<ProjectSaveTask *>(psm)->SetLayout(
main_window_->SaveLayout());
if (!override_filename.isEmpty()) {
// Set override filename if provided
static_cast<ProjectSaveTask*>(psm)->SetOverrideFilename(override_filename);
static_cast<ProjectSaveTask *>(psm)->SetOverrideFilename(
override_filename);
}
}
@@ -844,26 +874,28 @@ void Core::SaveProjectInternal(const QString& override_filename)
ViewerOutput *Core::GetSequenceToExport()
{
// First try the most recently focused time based window
TimeBasedPanel* time_panel = PanelManager::instance()->MostRecentlyFocused<TimeBasedPanel>();
TimeBasedPanel *time_panel =
PanelManager::instance()->MostRecentlyFocused<TimeBasedPanel>();
// If that fails try defaulting to the first timeline (i.e. if a project has just been loaded).
if (!time_panel->GetConnectedViewer()) {
// Safe to assume there will always be one timeline.
time_panel = PanelManager::instance()->GetPanelsOfType<TimelinePanel>().first();
time_panel =
PanelManager::instance()->GetPanelsOfType<TimelinePanel>().first();
}
if (time_panel && time_panel->GetConnectedViewer()) {
if (time_panel->GetConnectedViewer()->GetLength() == 0) {
QMessageBox::critical(main_window_,
tr("Error"),
QMessageBox::critical(
main_window_, tr("Error"),
tr("This Sequence is empty. There is nothing to export."),
QMessageBox::Ok);
} else {
return time_panel->GetConnectedViewer();
}
} else {
QMessageBox::critical(main_window_,
tr("Error"),
QMessageBox::critical(
main_window_, tr("Error"),
tr("No valid sequence detected.\n\nMake sure a sequence is loaded and it has a connected Viewer node."),
QMessageBox::Ok);
}
@@ -873,7 +905,9 @@ ViewerOutput *Core::GetSequenceToExport()
QString Core::GetAutoRecoveryIndexFilename()
{
return QDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(QStringLiteral("unrecovered"));
return QDir(QStandardPaths::writableLocation(
QStandardPaths::AppLocalDataLocation))
.filePath(QStringLiteral("unrecovered"));
}
void Core::SaveUnrecoveredList()
@@ -908,20 +942,27 @@ void Core::SaveUnrecoveredList()
bool Core::RevertProjectInternal(bool by_opening_existing)
{
if (open_project_->filename().isEmpty()) {
QMessageBox::critical(main_window_, tr("Revert"),
QMessageBox::critical(
main_window_, tr("Revert"),
tr("This project has not yet been saved, therefore there is no last saved state to revert to."));
} else {
QString msg;
if (by_opening_existing) {
msg = tr("The project \"%1\" is already open. By re-opening it, the project will revert to "
"its last saved state. Any unsaved changes will be lost. Do you wish to continue?").arg(open_project_->filename());
msg =
tr("The project \"%1\" is already open. By re-opening it, the project will revert to "
"its last saved state. Any unsaved changes will be lost. Do you wish to continue?")
.arg(open_project_->filename());
} else {
msg = tr("This will revert the project \"%1\" back to its last saved state. "
"All unsaved changes will be lost. Do you wish to continue?").arg(open_project_->name());
msg =
tr("This will revert the project \"%1\" back to its last saved state. "
"All unsaved changes will be lost. Do you wish to continue?")
.arg(open_project_->name());
}
if (QMessageBox::question(main_window_, tr("Revert"), msg, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
if (QMessageBox::question(main_window_, tr("Revert"), msg,
QMessageBox::Ok | QMessageBox::Cancel) ==
QMessageBox::Ok) {
// Copy filename because CloseProject is going to delete `p`
QString filename = open_project_->filename();
@@ -954,16 +995,22 @@ void Core::SaveAutorecovery()
{
if (OLIVE_CONFIG("AutorecoveryEnabled").toBool()) {
if (open_project_ && !open_project_->has_autorecovery_been_saved()) {
QDir project_autorecovery_dir(QDir(FileFunctions::GetAutoRecoveryRoot()).filePath(open_project_->GetUuid().toString()));
QDir project_autorecovery_dir(
QDir(FileFunctions::GetAutoRecoveryRoot())
.filePath(open_project_->GetUuid().toString()));
if (FileFunctions::DirectoryIsValid(project_autorecovery_dir)) {
QString this_autorecovery_path = project_autorecovery_dir.filePath(QStringLiteral("%1.ove").arg(QString::number(QDateTime::currentSecsSinceEpoch())));
QString this_autorecovery_path =
project_autorecovery_dir.filePath(
QStringLiteral("%1.ove").arg(QString::number(
QDateTime::currentSecsSinceEpoch())));
SaveProjectInternal(this_autorecovery_path);
open_project_->set_autorecovery_saved(true);
// Keep track of projects that where the "newest" save is the recovery project
if (!autorecovered_projects_.contains(open_project_->GetUuid())) {
if (!autorecovered_projects_.contains(
open_project_->GetUuid())) {
autorecovered_projects_.append(open_project_->GetUuid());
}
@@ -971,27 +1018,34 @@ void Core::SaveAutorecovery()
// Write human-readable real name so it's not just a UUID
{
QFile realname_file(project_autorecovery_dir.filePath(QStringLiteral("realname.txt")));
QFile realname_file(project_autorecovery_dir.filePath(
QStringLiteral("realname.txt")));
realname_file.open(QFile::WriteOnly);
realname_file.write(open_project_->pretty_filename().toUtf8());
realname_file.write(
open_project_->pretty_filename().toUtf8());
realname_file.close();
}
int64_t max_recoveries_per_file = OLIVE_CONFIG("AutorecoveryMaximum").toLongLong();
int64_t max_recoveries_per_file =
OLIVE_CONFIG("AutorecoveryMaximum").toLongLong();
// Since we write an extra file, increment total allowed files by 1
max_recoveries_per_file++;
// Delete old entries
QStringList recovery_files = project_autorecovery_dir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
QStringList recovery_files = project_autorecovery_dir.entryList(
QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
while (recovery_files.size() > max_recoveries_per_file) {
bool deleted = false;
for (int i = 0; i < recovery_files.size(); i++) {
const QString &f = recovery_files.at(i);
if (f.endsWith(QStringLiteral(".ove"), Qt::CaseInsensitive)) {
QString delete_full_path = project_autorecovery_dir.filePath(f);
qDebug() << "Deleted old recovery:" << delete_full_path;
if (f.endsWith(QStringLiteral(".ove"),
Qt::CaseInsensitive)) {
QString delete_full_path =
project_autorecovery_dir.filePath(f);
qDebug()
<< "Deleted old recovery:" << delete_full_path;
QFile::remove(delete_full_path);
recovery_files.removeAt(i);
deleted = true;
@@ -1006,7 +1060,8 @@ void Core::SaveAutorecovery()
}
}
} else {
QMessageBox::critical(main_window_, tr("Auto-Recovery Error"),
QMessageBox::critical(
main_window_, tr("Auto-Recovery Error"),
tr("Failed to save auto-recovery to \"%1\". "
"Olive may not have permission to this directory.")
.arg(project_autorecovery_dir.absolutePath()));
@@ -1039,7 +1094,8 @@ Project* Core::GetActiveProject() const
Folder *Core::GetSelectedFolderInActiveProject() const
{
ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused<ProjectPanel>();
ProjectPanel *active_project_panel =
PanelManager::instance()->MostRecentlyFocused<ProjectPanel>();
if (active_project_panel) {
return active_project_panel->GetSelectedFolder();
@@ -1050,7 +1106,8 @@ Folder *Core::GetSelectedFolderInActiveProject() const
Timecode::Display Core::GetTimecodeDisplay() const
{
return static_cast<Timecode::Display>(OLIVE_CONFIG("TimecodeDisplay").toInt());
return static_cast<Timecode::Display>(
OLIVE_CONFIG("TimecodeDisplay").toInt());
}
void Core::SetTimecodeDisplay(Timecode::Display d)
@@ -1099,7 +1156,8 @@ QString Core::GetProjectFilter(bool include_any_filter)
for (auto it = FILTERS.cbegin(); it != FILTERS.cend(); it++) {
combined.append(QStringLiteral("*.%1").arg(it->second));
}
filters.append(QStringLiteral("%1 (%2)").arg(tr("All Supported Projects"), combined.join(' ')));
filters.append(QStringLiteral("%1 (%2)").arg(
tr("All Supported Projects"), combined.join(' ')));
}
for (auto it = FILTERS.cbegin(); it != FILTERS.cend(); it++) {
@@ -1111,17 +1169,20 @@ QString Core::GetProjectFilter(bool include_any_filter)
QString Core::GetRecentProjectsFilePath()
{
return QDir(FileFunctions::GetConfigurationLocation()).filePath(QStringLiteral("recent"));
return QDir(FileFunctions::GetConfigurationLocation())
.filePath(QStringLiteral("recent"));
}
void Core::SetStartupLocale()
{
// Set language
if (!core_params_.startup_language().isEmpty()) {
if (translator_->load(core_params_.startup_language()) && QApplication::installTranslator(translator_)) {
if (translator_->load(core_params_.startup_language()) &&
QApplication::installTranslator(translator_)) {
return;
} else {
qWarning() << "Failed to load translation file. Falling back to defaults.";
qWarning()
<< "Failed to load translation file. Falling back to defaults.";
}
}
@@ -1133,7 +1194,8 @@ void Core::SetStartupLocale()
}
if (!SetLanguage(use_locale)) {
qWarning() << "Trying to use locale" << use_locale << "but couldn't find a translation for it";
qWarning() << "Trying to use locale" << use_locale
<< "but couldn't find a translation for it";
}
}
@@ -1168,12 +1230,15 @@ void Core::OpenNodeInViewer(ViewerOutput *viewer)
main_window_->OpenNodeInViewer(viewer);
}
void Core::OpenExportDialogForViewer(ViewerOutput *viewer, bool start_still_image)
void Core::OpenExportDialogForViewer(ViewerOutput *viewer,
bool start_still_image)
{
ExportDialog* ed = new ExportDialog(viewer, start_still_image, main_window_);
ExportDialog *ed =
new ExportDialog(viewer, start_still_image, main_window_);
connect(ed, &ExportDialog::finished, ed, &ExportDialog::deleteLater);
ed->open();
connect(ed, &ExportDialog::RequestImportFile, this, &Core::ImportSingleFile);
connect(ed, &ExportDialog::RequestImportFile, this,
&Core::ImportSingleFile);
}
void Core::CheckForAutoRecoveries()
@@ -1182,9 +1247,11 @@ void Core::CheckForAutoRecoveries()
if (autorecovery_index.exists()) {
// Uh-oh, we have auto-recoveries to prompt
if (autorecovery_index.open(QFile::ReadOnly)) {
QStringList recovery_filenames = QString::fromUtf8(autorecovery_index.readAll()).split('\n');
QStringList recovery_filenames =
QString::fromUtf8(autorecovery_index.readAll()).split('\n');
AutoRecoveryDialog ard(tr("The following projects had unsaved changes when Olive "
AutoRecoveryDialog ard(
tr("The following projects had unsaved changes when Olive "
"forcefully quit. Would you like to load them?"),
recovery_filenames, true, main_window_);
ard.exec();
@@ -1194,10 +1261,12 @@ void Core::CheckForAutoRecoveries()
// Delete recovery index since we don't need it anymore
QFile::remove(GetAutoRecoveryIndexFilename());
} else {
QMessageBox::critical(main_window_, tr("Auto-Recovery Error"),
QMessageBox::critical(
main_window_, tr("Auto-Recovery Error"),
tr("Found auto-recoveries but failed to load the auto-recovery index. "
"Auto-recover projects will have to be opened manually.\n\n"
"Your recoverable projects are still available at: %1").arg(FileFunctions::GetAutoRecoveryRoot()));
"Your recoverable projects are still available at: %1")
.arg(FileFunctions::GetAutoRecoveryRoot()));
}
}
}
@@ -1205,8 +1274,10 @@ void Core::CheckForAutoRecoveries()
void Core::BrowseAutoRecoveries()
{
// List all auto-recovery entries
AutoRecoveryDialog ard(tr("The following project versions have been auto-saved:"),
QDir(FileFunctions::GetAutoRecoveryRoot()).entryList(QDir::Dirs | QDir::NoDotAndDotDot),
AutoRecoveryDialog ard(
tr("The following project versions have been auto-saved:"),
QDir(FileFunctions::GetAutoRecoveryRoot())
.entryList(QDir::Dirs | QDir::NoDotAndDotDot),
false, main_window_);
ard.exec();
}
@@ -1235,7 +1306,8 @@ void Core::WarnCacheFull()
if (!shown_cache_full_warning_ && main_window_) {
shown_cache_full_warning_ = true;
QMessageBox::warning(main_window_, tr("Disk Cache Full"),
QMessageBox::warning(
main_window_, tr("Disk Cache Full"),
tr("The disk cache is currently full and Olive is having to delete old "
"frames to keep it within the limits set in the Disk preferences. This "
"will result in SIGNIFICANTLY reduced cache performance.\n\n"
@@ -1259,7 +1331,8 @@ bool Core::SaveProjectAs()
// Somewhat hacky method of extracting the extension from the name filter
const QString &name_filter = fd.selectedNameFilter();
int ext_index = name_filter.indexOf(QStringLiteral("(*.")) + 3;
QString extension = name_filter.mid(ext_index, name_filter.size() - ext_index - 1);
QString extension =
name_filter.mid(ext_index, name_filter.size() - ext_index - 1);
fn = FileFunctions::EnsureFilenameExtension(fn, extension);
@@ -1328,8 +1401,8 @@ void Core::OpenProjectInternal(const QString &filename, bool recovery_project)
#ifdef USE_OTIO
load_task = new LoadOTIOTask(filename);
#else
QMessageBox::critical(main_window_,
tr("Missing OpenTimelineIO Libraries"),
QMessageBox::critical(
main_window_, tr("Missing OpenTimelineIO Libraries"),
tr("This build was compiled without OpenTimelineIO and therefore "
"cannot open OpenTimelineIO files."));
return;
@@ -1339,12 +1412,15 @@ void Core::OpenProjectInternal(const QString &filename, bool recovery_project)
load_task = new ProjectLoadTask(filename);
}
TaskDialog* task_dialog = new TaskDialog(load_task, tr("Load Project"), main_window());
TaskDialog *task_dialog =
new TaskDialog(load_task, tr("Load Project"), main_window());
if (recovery_project) {
connect(task_dialog, &TaskDialog::TaskSucceeded, this, &Core::AddRecoveryProjectFromTask);
connect(task_dialog, &TaskDialog::TaskSucceeded, this,
&Core::AddRecoveryProjectFromTask);
} else {
connect(task_dialog, &TaskDialog::TaskSucceeded, this, &Core::AddOpenProjectFromTaskAndAddToRecents);
connect(task_dialog, &TaskDialog::TaskSucceeded, this,
&Core::AddOpenProjectFromTaskAndAddToRecents);
}
task_dialog->open();
@@ -1366,7 +1442,8 @@ int Core::CountFilesInFileList(const QFileInfoList &filenames)
if (f.fileName() == "." || f.fileName() == "..") {
continue;
} else if (f.isDir()) {
QFileInfoList info_list = QDir(f.absoluteFilePath()).entryInfoList();
QFileInfoList info_list =
QDir(f.absoluteFilePath()).entryInfoList();
file_count += CountFilesInFileList(info_list);
} else {
@@ -1395,12 +1472,9 @@ bool Core::LabelNodes(const QVector<Node *> &nodes, MultiUndoCommand *parent)
}
}
QString s = QInputDialog::getText(main_window_,
tr("Label Node"),
tr("Set node label"),
QLineEdit::Normal,
start_label,
&ok);
QString s = QInputDialog::getText(main_window_, tr("Label Node"),
tr("Set node label"), QLineEdit::Normal,
start_label, &ok);
if (ok) {
NodeRenameCommand *rename_command = new NodeRenameCommand();
@@ -1412,7 +1486,8 @@ bool Core::LabelNodes(const QVector<Node *> &nodes, MultiUndoCommand *parent)
if (parent) {
parent->add_child(rename_command);
} else {
undo_stack_.push(rename_command, tr("Renamed %1 Node(s)").arg(nodes.size()));
undo_stack_.push(rename_command,
tr("Renamed %1 Node(s)").arg(nodes.size()));
}
return true;
@@ -1421,7 +1496,8 @@ bool Core::LabelNodes(const QVector<Node *> &nodes, MultiUndoCommand *parent)
return false;
}
Sequence *Core::CreateNewSequenceForProject(const QString &format, Project* project)
Sequence *Core::CreateNewSequenceForProject(const QString &format,
Project *project)
{
Sequence *new_sequence = new Sequence();
@@ -1443,9 +1519,11 @@ void Core::OpenProjectFromRecentList(int index)
if (QFileInfo::exists(open_fn)) {
OpenProjectInternal(open_fn);
} else if (QMessageBox::information(main_window(),
tr("Cannot open recent project"),
tr("The project \"%1\" doesn't exist. Would you like to remove this file from the recent list?").arg(open_fn),
} else if (
QMessageBox::information(
main_window(), tr("Cannot open recent project"),
tr("The project \"%1\" doesn't exist. Would you like to remove this file from the recent list?")
.arg(open_fn),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
recent_projects_.removeAt(index);
@@ -1464,10 +1542,12 @@ bool Core::CloseProject(bool auto_open_new, bool ignore_modified)
mb.setWindowModality(Qt::WindowModal);
mb.setIcon(QMessageBox::Question);
mb.setWindowTitle(tr("Unsaved Changes"));
mb.setText(tr("The project '%1' has unsaved changes. Would you like to save them?")
mb.setText(
tr("The project '%1' has unsaved changes. Would you like to save them?")
.arg(open_project_->name()));
QPushButton* yes_btn = mb.addButton(tr("Save"), QMessageBox::YesRole);
QPushButton *yes_btn =
mb.addButton(tr("Save"), QMessageBox::YesRole);
mb.addButton(tr("Don't Save"), QMessageBox::NoRole);
@@ -1504,13 +1584,15 @@ bool Core::CloseProject(bool auto_open_new, bool ignore_modified)
void Core::CacheActiveSequence(bool in_out_only)
{
TimeBasedPanel* p = PanelManager::instance()->MostRecentlyFocused<TimeBasedPanel>();
TimeBasedPanel *p =
PanelManager::instance()->MostRecentlyFocused<TimeBasedPanel>();
if (p && p->GetConnectedViewer()) {
// Hacky but works for now
// Find Viewer attached to this TimeBasedPanel
QList<ViewerPanel*> all_viewers = PanelManager::instance()->GetPanelsOfType<ViewerPanel>();
QList<ViewerPanel *> all_viewers =
PanelManager::instance()->GetPanelsOfType<ViewerPanel>();
ViewerPanel *found_panel = nullptr;
@@ -1528,8 +1610,8 @@ void Core::CacheActiveSequence(bool in_out_only)
found_panel->CacheEntireSequence();
}
} else {
QMessageBox::critical(main_window_,
tr("Failed to cache sequence"),
QMessageBox::critical(
main_window_, tr("Failed to cache sequence"),
tr("No active viewer found with this sequence."),
QMessageBox::Ok);
}
@@ -1558,7 +1640,8 @@ QString StripWindowsDriveLetter(QString s)
return s;
}
bool Core::ValidateFootageInLoadedProject(Project* project, const QString& project_saved_url)
bool Core::ValidateFootageInLoadedProject(Project *project,
const QString &project_saved_url)
{
QVector<Footage *> footage_we_couldnt_validate;
@@ -1567,7 +1650,8 @@ bool Core::ValidateFootageInLoadedProject(Project* project, const QString& proje
QString footage_fn = StripWindowsDriveLetter(footage->filename());
QString project_fn = StripWindowsDriveLetter(project_saved_url);
if (!QFileInfo::exists(footage_fn) && !project_saved_url.isEmpty()) {
if (!QFileInfo::exists(footage_fn) &&
!project_saved_url.isEmpty()) {
// If the footage doesn't exist, it might have moved with the project
const QString &project_current_url = project->filename();
@@ -1576,12 +1660,15 @@ bool Core::ValidateFootageInLoadedProject(Project* project, const QString& proje
QDir saved_dir(QFileInfo(project_fn).dir());
QDir true_dir(QFileInfo(project_current_url).dir());
QString relative_filename = saved_dir.relativeFilePath(footage_fn);
QString transformed_abs_filename = true_dir.filePath(relative_filename);
QString relative_filename =
saved_dir.relativeFilePath(footage_fn);
QString transformed_abs_filename =
true_dir.filePath(relative_filename);
if (QFileInfo::exists(transformed_abs_filename)) {
// Use this file instead
qInfo() << "Resolved" << footage_fn << "relatively to" << transformed_abs_filename;
qInfo() << "Resolved" << footage_fn << "relatively to"
<< transformed_abs_filename;
footage->set_filename(transformed_abs_filename);
}
}
@@ -1611,7 +1698,8 @@ bool Core::SetLanguage(const QString &locale)
QApplication::removeTranslator(translator_);
QString resource_path = QStringLiteral(":/ts/%1").arg(locale);
if (translator_->load(resource_path) && QApplication::installTranslator(translator_)) {
if (translator_->load(resource_path) &&
QApplication::installTranslator(translator_)) {
return true;
}
@@ -1620,20 +1708,18 @@ bool Core::SetLanguage(const QString &locale)
void Core::OpenProject()
{
QString file = QFileDialog::getOpenFileName(main_window_,
tr("Open Project"),
QString(),
GetProjectFilter(true));
QString file = QFileDialog::getOpenFileName(
main_window_, tr("Open Project"), QString(), GetProjectFilter(true));
if (!file.isEmpty()) {
OpenProjectInternal(file);
}
}
Core::CoreParams::CoreParams() :
mode_(kRunNormal),
run_fullscreen_(false),
crash_(false)
Core::CoreParams::CoreParams()
: mode_(kRunNormal)
, run_fullscreen_(false)
, crash_(false)
{
}
+19 -18
View File
@@ -35,7 +35,8 @@
#include "undo/undostack.h"
#include "widget/projectexplorer/projectviewmodel.h"
namespace olive {
namespace olive
{
class MainWindow;
@@ -48,20 +49,14 @@ class MainWindow;
* The "public slots" are usually user-triggered actions and can be connected to UI elements (e.g. creating a folder,
* opening the import dialog, etc.)
*/
class Core : public QObject
{
class Core : public QObject {
Q_OBJECT
public:
class CoreParams
{
class CoreParams {
public:
CoreParams();
enum RunMode {
kRunNormal,
kHeadlessExport,
kHeadlessPreCache
};
enum RunMode { kRunNormal, kHeadlessExport, kHeadlessPreCache };
bool fullscreen() const
{
@@ -123,7 +118,6 @@ public:
bool run_fullscreen_;
bool crash_;
};
/**
@@ -248,12 +242,14 @@ public:
/**
* @brief Show a dialog to the user to rename a set of nodes
*/
bool LabelNodes(const QVector<Node *> &nodes, MultiUndoCommand *parent = nullptr);
bool LabelNodes(const QVector<Node *> &nodes,
MultiUndoCommand *parent = nullptr);
/**
* @brief Create a new sequence named appropriately for the active project
*/
static Sequence* CreateNewSequenceForProject(const QString &format, Project *project);
static Sequence *CreateNewSequenceForProject(const QString &format,
Project *project);
static Sequence *CreateNewSequenceForProject(Project *project)
{
return CreateNewSequenceForProject(tr("Sequence %1"), project);
@@ -277,7 +273,8 @@ public:
/**
* @brief Check each footage object for whether it still exists or has changed
*/
bool ValidateFootageInLoadedProject(Project* project, const QString &project_saved_url);
bool ValidateFootageInLoadedProject(Project *project,
const QString &project_saved_url);
/**
* @brief Changes the current language
@@ -297,9 +294,13 @@ public:
void OpenNodeInViewer(ViewerOutput *viewer);
void OpenExportDialogForViewer(ViewerOutput *viewer, bool start_still_image);
void OpenExportDialogForViewer(ViewerOutput *viewer,
bool start_still_image);
bool IsMagicEnabled() const { return magic_; }
bool IsMagicEnabled() const
{
return magic_;
}
public slots:
/**
@@ -610,10 +611,10 @@ private slots:
/**
* @brief Internal project open
*/
void OpenProjectInternal(const QString& filename, bool recovery_project = false);
void OpenProjectInternal(const QString &filename,
bool recovery_project = false);
void ImportSingleFile(const QString &f);
};
}
+66 -31
View File
@@ -40,7 +40,8 @@
#include "common/filefunctions.h"
#include "version.h"
namespace olive {
namespace olive
{
CrashHandlerDialog::CrashHandlerDialog(const QString &report_path)
{
@@ -52,7 +53,8 @@ CrashHandlerDialog::CrashHandlerDialog(const QString& report_path)
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(new QLabel(tr("We're sorry, Olive has crashed. Please help us fix it by "
layout->addWidget(new QLabel(
tr("We're sorry, Olive has crashed. Please help us fix it by "
"sending an error report.")));
QSplitter *splitter = new QSplitter(Qt::Vertical);
@@ -60,7 +62,8 @@ CrashHandlerDialog::CrashHandlerDialog(const QString& report_path)
layout->addWidget(splitter);
summary_edit_ = new QTextEdit();
summary_edit_->setPlaceholderText(tr("Describe what you were doing in as much detail as "
summary_edit_->setPlaceholderText(
tr("Describe what you were doing in as much detail as "
"possible. If you can, provide steps to reproduce this crash."));
splitter->addWidget(summary_edit_);
@@ -83,11 +86,13 @@ CrashHandlerDialog::CrashHandlerDialog(const QString& report_path)
btn_layout->addStretch();
send_report_btn_ = new QPushButton(tr("Send Error Report"));
connect(send_report_btn_, &QPushButton::clicked, this, &CrashHandlerDialog::SendErrorReport);
connect(send_report_btn_, &QPushButton::clicked, this,
&CrashHandlerDialog::SendErrorReport);
btn_layout->addWidget(send_report_btn_);
dont_send_btn_ = new QPushButton(tr("Don't Send"));
connect(dont_send_btn_, &QPushButton::clicked, this, &CrashHandlerDialog::reject);
connect(dont_send_btn_, &QPushButton::clicked, this,
&CrashHandlerDialog::reject);
btn_layout->addWidget(dont_send_btn_);
layout->addLayout(btn_layout);
@@ -117,7 +122,8 @@ QString CrashHandlerDialog::GetSymbolPath()
symbols_path = app_path.filePath(QStringLiteral("symbols"));
#elif BUILDFLAG(IS_LINUX)
app_path.cdUp();
symbols_path = app_path.filePath(QStringLiteral("share/olive-editor/symbols"));
symbols_path =
app_path.filePath(QStringLiteral("share/olive-editor/symbols"));
#elif BUILDFLAG(IS_APPLE)
app_path.cdUp();
symbols_path = app_path.filePath(QStringLiteral("Resources/symbols"));
@@ -132,13 +138,18 @@ void CrashHandlerDialog::GenerateReport()
connect(p, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &CrashHandlerDialog::ReadProcessFinished);
connect(p, &QProcess::readyReadStandardOutput, this, &CrashHandlerDialog::ReadProcessHasData);
connect(p, &QProcess::readyReadStandardOutput, this,
&CrashHandlerDialog::ReadProcessHasData);
QString stackwalk_filename = FileFunctions::GetFormattedExecutableForPlatform(QStringLiteral("minidump_stackwalk"));
QString stackwalk_filename =
FileFunctions::GetFormattedExecutableForPlatform(
QStringLiteral("minidump_stackwalk"));
QString stackwalk_bin = QDir(qApp->applicationDirPath()).filePath(stackwalk_filename);
QString stackwalk_bin =
QDir(qApp->applicationDirPath()).filePath(stackwalk_filename);
p->start(stackwalk_bin, { report_filename_, GetSymbolPath() });
crash_report_->setText(QStringLiteral("Trying to run: %1").arg(stackwalk_bin));
crash_report_->setText(
QStringLiteral("Trying to run: %1").arg(stackwalk_bin));
}
void CrashHandlerDialog::ReplyFinished(QNetworkReply *reply)
@@ -153,7 +164,9 @@ void CrashHandlerDialog::ReplyFinished(QNetworkReply* reply)
b.setIcon(QMessageBox::Critical);
b.setWindowModality(Qt::WindowModal);
b.setWindowTitle(tr("Upload Failed"));
b.setText(tr("Failed to send error report (%1). Please try again later.").arg(QString::number(reply->error())));
b.setText(
tr("Failed to send error report (%1). Please try again later.")
.arg(QString::number(reply->error())));
b.addButton(QMessageBox::Ok);
b.exec();
@@ -161,7 +174,8 @@ void CrashHandlerDialog::ReplyFinished(QNetworkReply* reply)
}
}
void CrashHandlerDialog::HandleSslErrors(QNetworkReply *reply, const QList<QSslError> &se)
void CrashHandlerDialog::HandleSslErrors(QNetworkReply *reply,
const QList<QSslError> &se)
{
QStringList errors;
for (const QSslError &err : se) {
@@ -172,7 +186,8 @@ void CrashHandlerDialog::HandleSslErrors(QNetworkReply *reply, const QList<QSslE
b.setIcon(QMessageBox::Critical);
b.setWindowModality(Qt::WindowModal);
b.setWindowTitle(tr("SSL Error"));
b.setText(tr("Encountered the following SSL errors:\n\n%1").arg(errors.join('\n')));
b.setText(tr("Encountered the following SSL errors:\n\n%1")
.arg(errors.join('\n')));
b.addButton(QMessageBox::Ok);
b.exec();
}
@@ -190,7 +205,8 @@ void CrashHandlerDialog::AttemptToFindReport()
void CrashHandlerDialog::ReadProcessHasData()
{
report_data_.append(static_cast<QProcess*>(sender())->readAllStandardOutput());
report_data_.append(
static_cast<QProcess *>(sender())->readAllStandardOutput());
}
void CrashHandlerDialog::ReadProcessFinished()
@@ -206,48 +222,62 @@ void CrashHandlerDialog::SendErrorReport()
QMessageBox b(this);
b.setIcon(QMessageBox::Question);
b.setWindowModality(Qt::WindowModal);
b.setText(tr("You must write a description to submit this crash report."));
b.setText(
tr("You must write a description to submit this crash report."));
b.addButton(QMessageBox::Ok);
b.exec();
return;
}
QNetworkAccessManager *manager = new QNetworkAccessManager();
connect(manager, &QNetworkAccessManager::finished, this, &CrashHandlerDialog::ReplyFinished);
connect(manager, &QNetworkAccessManager::sslErrors, this, &CrashHandlerDialog::HandleSslErrors);
connect(manager, &QNetworkAccessManager::finished, this,
&CrashHandlerDialog::ReplyFinished);
connect(manager, &QNetworkAccessManager::sslErrors, this,
&CrashHandlerDialog::HandleSslErrors);
QNetworkRequest request;
request.setSslConfiguration(QSslConfiguration::defaultConfiguration());
request.setUrl(QStringLiteral("https://olivevideoeditor.org/crashpad/report.php"));
request.setUrl(
QStringLiteral("https://olivevideoeditor.org/crashpad/report.php"));
// Create HTTP form
QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpMultiPart *multipart =
new QHttpMultiPart(QHttpMultiPart::FormDataType);
// Create description section
QHttpPart desc_part;
desc_part.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("text/plain; charset=UTF-8"));
desc_part.setHeader(QNetworkRequest::ContentDispositionHeader, QStringLiteral("form-data; name=\"description\""));
desc_part.setHeader(QNetworkRequest::ContentTypeHeader,
QStringLiteral("text/plain; charset=UTF-8"));
desc_part.setHeader(QNetworkRequest::ContentDispositionHeader,
QStringLiteral("form-data; name=\"description\""));
desc_part.setBody(summary_edit_->toPlainText().toUtf8());
multipart->append(desc_part);
// Create report section
QHttpPart report_part;
report_part.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("text/plain; charset=UTF-8"));
report_part.setHeader(QNetworkRequest::ContentDispositionHeader, QStringLiteral("form-data; name=\"report\""));
report_part.setHeader(QNetworkRequest::ContentTypeHeader,
QStringLiteral("text/plain; charset=UTF-8"));
report_part.setHeader(QNetworkRequest::ContentDispositionHeader,
QStringLiteral("form-data; name=\"report\""));
report_part.setBody(report_data_);
multipart->append(report_part);
// Create commit section
QHttpPart commit_part;
commit_part.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("text/plain; charset=UTF-8"));
commit_part.setHeader(QNetworkRequest::ContentDispositionHeader, QStringLiteral("form-data; name=\"commit\""));
commit_part.setHeader(QNetworkRequest::ContentTypeHeader,
QStringLiteral("text/plain; charset=UTF-8"));
commit_part.setHeader(QNetworkRequest::ContentDispositionHeader,
QStringLiteral("form-data; name=\"commit\""));
commit_part.setBody(kAppVersionLong.toUtf8());
multipart->append(commit_part);
// Create dump section
QHttpPart dump_part;
dump_part.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/octet-stream"));
dump_part.setHeader(QNetworkRequest::ContentDispositionHeader, QStringLiteral("form-data; name=\"dump\"; filename=\"%1\"")
dump_part.setHeader(QNetworkRequest::ContentTypeHeader,
QStringLiteral("application/octet-stream"));
dump_part.setHeader(
QNetworkRequest::ContentDispositionHeader,
QStringLiteral("form-data; name=\"dump\"; filename=\"%1\"")
.arg(QFileInfo(report_filename_).fileName()));
QFile *dump_file = new QFile(report_filename_);
dump_file->open(QFile::ReadOnly);
@@ -268,7 +298,8 @@ void CrashHandlerDialog::SendErrorReport()
#endif
symbol_dir = QDir(symbol_dir.filePath(symbol_bin_name));
QStringList folders_in_symbol_path = symbol_dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
QStringList folders_in_symbol_path =
symbol_dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
if (folders_in_symbol_path.size() > 0) {
symbol_dir = QDir(symbol_dir.filePath(folders_in_symbol_path.first()));
@@ -294,8 +325,11 @@ void CrashHandlerDialog::SendErrorReport()
#endif
QString symbol_full_path = symbol_dir.filePath(symbol_filename);
QHttpPart sym_part;
sym_part.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/octet-stream"));
sym_part.setHeader(QNetworkRequest::ContentDispositionHeader, QStringLiteral("form-data; name=\"sym\"; filename=\"%1\"")
sym_part.setHeader(QNetworkRequest::ContentTypeHeader,
QStringLiteral("application/octet-stream"));
sym_part.setHeader(
QNetworkRequest::ContentDispositionHeader,
QStringLiteral("form-data; name=\"sym\"; filename=\"%1\"")
.arg(symbol_filename));
QFile sym_file(symbol_full_path);
@@ -329,7 +363,8 @@ void CrashHandlerDialog::closeEvent(QCloseEvent* e)
b.setIcon(QMessageBox::Warning);
b.setWindowModality(Qt::WindowModal);
b.setWindowTitle(tr("Confirm Close"));
b.setText(tr("Crash report is still uploading. Closing now may result in no "
b.setText(
tr("Crash report is still uploading. Closing now may result in no "
"report being sent. Are you sure you wish to close?"));
b.addButton(QMessageBox::Ok);
b.addButton(QMessageBox::Cancel);
+3 -4
View File
@@ -30,10 +30,10 @@
#include "common/define.h"
namespace olive {
class CrashHandlerDialog : public QDialog
namespace olive
{
class CrashHandlerDialog : public QDialog {
Q_OBJECT
public:
CrashHandlerDialog(const QString &report_path);
@@ -74,7 +74,6 @@ private slots:
void ReadProcessFinished();
void SendErrorReport();
};
}
+30 -17
View File
@@ -30,13 +30,15 @@
#include "patreon.h"
#include "scrollinglabel.h"
namespace olive {
namespace olive
{
AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) :
QDialog(parent)
AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent)
: QDialog(parent)
{
if (welcome_dialog) {
setWindowTitle(tr("Welcome to %1").arg(QApplication::applicationName()));
setWindowTitle(
tr("Welcome to %1").arg(QApplication::applicationName()));
} else {
setWindowTitle(tr("About %1").arg(QApplication::applicationName()));
}
@@ -44,25 +46,29 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) :
QFontMetrics fm = fontMetrics();
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(fm.height(), fm.height(), fm.height(), fm.height());
layout->setContentsMargins(fm.height(), fm.height(), fm.height(),
fm.height());
QHBoxLayout *horiz_layout = new QHBoxLayout();
horiz_layout->setContentsMargins(fm.height(), fm.height(), fm.height(), fm.height());
horiz_layout->setContentsMargins(fm.height(), fm.height(), fm.height(),
fm.height());
horiz_layout->setSpacing(fm.height() * 2);
QLabel* icon = new QLabel(QStringLiteral("<html><img src=':/graphics/olive-splash.png'></html>"));
QLabel *icon = new QLabel(
QStringLiteral("<html><img src=':/graphics/olive-splash.png'></html>"));
icon->setAlignment(Qt::AlignCenter);
horiz_layout->addWidget(icon);
// Construct About text
QLabel* label =
new QLabel(QStringLiteral("<html><head/><body>"
QLabel *label = new QLabel(
QStringLiteral("<html><head/><body>"
"<p><b>%1</b> %2</p>" // AppName (version identifier)
"<p><a href=\"https://www.olivevideoeditor.org/\">"
"https://www.olivevideoeditor.org/"
"</a></p>"
"<p>%3</p>" // First statement
"</body></html>").arg(QApplication::applicationName(),
"</body></html>")
.arg(QApplication::applicationName(),
QApplication::applicationVersion(),
tr("Olive is a free open source non-linear video editor. "
"This software is licensed under the GNU GPL Version 3.")));
@@ -72,7 +78,8 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) :
label->setWordWrap(true);
label->setOpenExternalLinks(true);
label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
label->setTextInteractionFlags(Qt::TextSelectableByMouse |
Qt::LinksAccessibleByMouse);
label->setCursor(Qt::IBeamCursor);
horiz_layout->addWidget(label);
@@ -84,16 +91,20 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) :
QString opening_statement;
if (welcome_dialog || patrons.isEmpty()) {
opening_statement = tr("<b>Olive relies on support from the community to continue its development.</b>");
opening_statement = tr(
"<b>Olive relies on support from the community to continue its development.</b>");
} else {
opening_statement = tr("Olive wouldn't be possible without the support of gracious donations from the following people.");
opening_statement = tr(
"Olive wouldn't be possible without the support of gracious donations from the following people.");
}
QLabel* support_lbl = new QLabel(tr("<html>%1 "
QLabel *support_lbl = new QLabel(
tr("<html>%1 "
"If you like this project, please consider making a "
"<a href='https://olivevideoeditor.org/donate.php'>one-time donation</a> or "
"<a href='https://www.patreon.com/olivevideoeditor'>pledging monthly</a> to "
"support its development.</html>").arg(opening_statement));
"support its development.</html>")
.arg(opening_statement));
support_lbl->setWordWrap(true);
support_lbl->setAlignment(Qt::AlignCenter);
support_lbl->setOpenExternalLinks(true);
@@ -112,13 +123,15 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) :
btn_layout->setSpacing(0);
if (welcome_dialog) {
dont_show_again_checkbox_ = new QCheckBox(tr("Don't show this message again"));
dont_show_again_checkbox_ =
new QCheckBox(tr("Don't show this message again"));
btn_layout->addWidget(dont_show_again_checkbox_);
} else {
dont_show_again_checkbox_ = nullptr;
}
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this);
QDialogButtonBox *buttons =
new QDialogButtonBox(QDialogButtonBox::Ok, this);
if (!welcome_dialog) {
buttons->setCenterButtons(true);
}
+3 -4
View File
@@ -26,7 +26,8 @@
#include "common/define.h"
namespace olive {
namespace olive
{
/**
* @brief The AboutDialog class
@@ -34,8 +35,7 @@ namespace olive {
* The About dialog (accessible through Help > About). Contains license and version information. This can be run from
* anywhere
*/
class AboutDialog : public QDialog
{
class AboutDialog : public QDialog {
Q_OBJECT
public:
/**
@@ -54,7 +54,6 @@ public slots:
private:
QCheckBox *dont_show_again_checkbox_;
};
}
+11 -8
View File
@@ -24,20 +24,21 @@
#include "common/qtutils.h"
namespace olive {
namespace olive
{
const int ScrollingLabel::kMinLineHeight = 10;
ScrollingLabel::ScrollingLabel(QWidget *parent) :
QWidget(parent),
animate_(0)
ScrollingLabel::ScrollingLabel(QWidget *parent)
: QWidget(parent)
, animate_(0)
{
timer_.setInterval(50);
connect(&timer_, &QTimer::timeout, this, &ScrollingLabel::AnimationUpdate);
}
ScrollingLabel::ScrollingLabel(const QStringList &text, QWidget *parent) :
ScrollingLabel(parent)
ScrollingLabel::ScrollingLabel(const QStringList &text, QWidget *parent)
: ScrollingLabel(parent)
{
SetText(text);
}
@@ -88,7 +89,8 @@ void ScrollingLabel::paintEvent(QPaintEvent *e)
double mul = double(y) / double(text_height_);
SetOpacityOfScanLine(map.scanLine(y), map.width(), 4, mul);
SetOpacityOfScanLine(map.scanLine(map.height()-1-y), map.width(), 4, mul);
SetOpacityOfScanLine(map.scanLine(map.height() - 1 - y),
map.width(), 4, mul);
}
}
@@ -96,7 +98,8 @@ void ScrollingLabel::paintEvent(QPaintEvent *e)
wp.drawImage(0, 0, map);
}
void ScrollingLabel::SetOpacityOfScanLine(uchar *scan_line, int width, int channels, double mul)
void ScrollingLabel::SetOpacityOfScanLine(uchar *scan_line, int width,
int channels, double mul)
{
for (int x = 0; x < width; x++) {
uchar *pixel = &scan_line[x * 4];
+5 -5
View File
@@ -24,10 +24,10 @@
#include <QTimer>
#include <QWidget>
namespace olive {
class ScrollingLabel : public QWidget
namespace olive
{
class ScrollingLabel : public QWidget {
Q_OBJECT
public:
ScrollingLabel(QWidget *parent = nullptr);
@@ -49,7 +49,8 @@ protected:
virtual void paintEvent(QPaintEvent *e) override;
private:
static void SetOpacityOfScanLine(uchar* scan_line, int width, int channels, double mul);
static void SetOpacityOfScanLine(uchar *scan_line, int width, int channels,
double mul);
static const int kMinLineHeight;
@@ -63,7 +64,6 @@ private:
private slots:
void AnimationUpdate();
};
}
+40 -36
View File
@@ -25,11 +25,12 @@
#include <QMenuBar>
#include <QVBoxLayout>
namespace olive {
namespace olive
{
ActionSearch::ActionSearch(QWidget *parent) :
QDialog(parent),
menu_bar_(nullptr)
ActionSearch::ActionSearch(QWidget *parent)
: QDialog(parent)
, menu_bar_(nullptr)
{
// ActionSearch requires a parent widget
Q_ASSERT(parent != nullptr);
@@ -58,13 +59,16 @@ ActionSearch::ActionSearch(QWidget *parent) :
entry_field->setPlaceholderText(tr("Search for action..."));
// Connect signals/slots
connect(entry_field, SIGNAL(textChanged(const QString&)), this, SLOT(search_update(const QString &)));
connect(entry_field, SIGNAL(textChanged(const QString &)), this,
SLOT(search_update(const QString &)));
connect(entry_field, SIGNAL(returnPressed()), this, SLOT(perform_action()));
// moveSelectionUp() and moveSelectionDown() are emitted when the user pressed up or down on the text field.
// We override it here to select the upper or lower item in the list.
connect(entry_field, SIGNAL(moveSelectionUp()), this, SLOT(move_selection_up()));
connect(entry_field, SIGNAL(moveSelectionDown()), this, SLOT(move_selection_down()));
connect(entry_field, SIGNAL(moveSelectionUp()), this,
SLOT(move_selection_up()));
connect(entry_field, SIGNAL(moveSelectionDown()), this,
SLOT(move_selection_down()));
layout->addWidget(entry_field);
// Construct list of actions
@@ -89,7 +93,8 @@ void ActionSearch::SetMenuBar(QMenuBar *menu_bar)
menu_bar_ = menu_bar;
}
void ActionSearch::search_update(const QString &s, const QString &p, QMenu *parent)
void ActionSearch::search_update(const QString &s, const QString &p,
QMenu *parent)
{
// Do nothing if there's no menu bar to work with
if (menu_bar_ == nullptr) {
@@ -102,7 +107,6 @@ void ActionSearch::search_update(const QString &s, const QString &p, QMenu *pare
// submenus).
if (parent == nullptr) {
// If parent is NULL, we'll pull from the MainWindow's menubar and call this recursively on all of its submenus
// (and their submenus).
@@ -125,31 +129,28 @@ void ActionSearch::search_update(const QString &s, const QString &p, QMenu *pare
}
} else {
// Parent was not NULL, so we loop over the actions in the menu we were given in `parent`.
// The list shows a '>' delimited hierarchy of the menus in which this action came from. We construct it here by
// adding the current menu's text to the existing hierarchy (passed in `p`).
QString menu_text;
if (!p.isEmpty()) menu_text += p + " > ";
menu_text += parent->title().replace("&", ""); // Strip out any &s used in menu action names
if (!p.isEmpty())
menu_text += p + " > ";
menu_text += parent->title().replace(
"&", ""); // Strip out any &s used in menu action names
// Loop over the menu's actions
QList<QAction *> actions = parent->actions();
for (int i = 0; i < actions.size(); i++) {
QAction *a = actions.at(i);
// Ignore separator actions
if (!a->isSeparator()) {
if (a->menu() != nullptr) {
// If the action is a menu, run this function recursively on it
search_update(s, menu_text, a->menu());
} else {
// This is a valid non-separator non-menu action, so check it against the currently entered string.
// Strip out all &s from the action's name
@@ -157,45 +158,43 @@ void ActionSearch::search_update(const QString &s, const QString &p, QMenu *pare
// See if the action's name contains any of the currently entered string
if (comp.contains(s, Qt::CaseInsensitive)) {
// If so, we add it to the list widget.
QListWidgetItem* item = new QListWidgetItem(QStringLiteral("%1\n(%2)").arg(comp, menu_text), list_widget);
QListWidgetItem *item = new QListWidgetItem(
QStringLiteral("%1\n(%2)").arg(comp, menu_text),
list_widget);
// Add a pointer to the original QAction in the item's data
item->setData(Qt::UserRole+1, reinterpret_cast<quintptr>(a));
item->setData(Qt::UserRole + 1,
reinterpret_cast<quintptr>(a));
list_widget->addItem(item);
}
}
}
}
}
}
void ActionSearch::perform_action() {
void ActionSearch::perform_action()
{
// Loop over all the items in the list and if we find one that's selected, we trigger it.
QList<QListWidgetItem *> selected_items = list_widget->selectedItems();
if (list_widget->count() > 0 && selected_items.size() > 0) {
QListWidgetItem *item = selected_items.at(0);
// Get QAction pointer from item's data
QAction* a = reinterpret_cast<QAction*>(item->data(Qt::UserRole+1).value<quintptr>());
QAction *a = reinterpret_cast<QAction *>(
item->data(Qt::UserRole + 1).value<quintptr>());
a->trigger();
}
// Close this popup
accept();
}
void ActionSearch::move_selection_up() {
void ActionSearch::move_selection_up()
{
// Here we loop over all the items to find the currently selected one, and then select the one above it. We start
// iterating at 1 (instead of 0) to efficiently ignore the first item (since the selection can't go below the very
// bottom item).
@@ -210,8 +209,8 @@ void ActionSearch::move_selection_up() {
}
}
void ActionSearch::move_selection_down() {
void ActionSearch::move_selection_down()
{
// Here we loop over all the items to find the currently selected one, and then select the one below it. We limit it
// one entry before count() to efficiently ignore the item at the end (since the selection can't go below the very
// bottom item).
@@ -226,7 +225,10 @@ void ActionSearch::move_selection_down() {
}
}
ActionSearchEntry::ActionSearchEntry(QWidget *parent) : QLineEdit(parent) {}
ActionSearchEntry::ActionSearchEntry(QWidget *parent)
: QLineEdit(parent)
{
}
bool ActionSearchEntry::event(QEvent *e)
{
@@ -259,13 +261,15 @@ bool ActionSearchEntry::event(QEvent *e)
return QLineEdit::event(e);
}
ActionSearchList::ActionSearchList(QWidget *parent) : QListWidget(parent) {}
void ActionSearchList::mouseDoubleClickEvent(QMouseEvent *) {
ActionSearchList::ActionSearchList(QWidget *parent)
: QListWidget(parent)
{
}
void ActionSearchList::mouseDoubleClickEvent(QMouseEvent *)
{
// Indiscriminately emit a signal on any double click
emit dbl_click();
}
}
+8 -4
View File
@@ -29,7 +29,8 @@
#include "common/define.h"
namespace olive {
namespace olive
{
class ActionSearchList;
@@ -39,8 +40,7 @@ class ActionSearchList;
* A popup window (accessible through Help > Action Search) that allows users to search for a menu command by typing
* rather than browsing through the menu bar. This can be created from anywhere provided olive::MainWindow is valid.
*/
class ActionSearch : public QDialog
{
class ActionSearch : public QDialog {
Q_OBJECT
public:
/**
@@ -82,7 +82,8 @@ private slots:
* The current menu to loop over. In most cases, this should be left as nullptr when called externally.
* search_update() will fill this automatically as it needs while calling itself recursively.
*/
void search_update(const QString& s, const QString &p = nullptr, QMenu *parent = nullptr);
void search_update(const QString &s, const QString &p = nullptr,
QMenu *parent = nullptr);
/**
* @brief Perform the currently selected action
@@ -108,6 +109,7 @@ private slots:
* selection is already at the bottom of the list, this is a no-op.
*/
void move_selection_down();
private:
/**
* @brief Main widget that shows the list of commands
@@ -136,6 +138,7 @@ public:
* Usually ActionSearch.
*/
ActionSearchList(QWidget *parent);
protected:
/**
* @brief Override of QListWidget's double click event that emits a signal.
@@ -164,6 +167,7 @@ public:
* Usually ActionSearch.
*/
ActionSearchEntry(QWidget *parent);
protected:
/**
* @brief Override of QLineEdit's key press event that listens for up/down key presses.
+34 -15
View File
@@ -29,12 +29,15 @@
#include "core.h"
namespace olive {
namespace olive
{
#define super QDialog
AutoRecoveryDialog::AutoRecoveryDialog(const QString &message, const QStringList &recoveries, bool autocheck_latest, QWidget* parent) :
QDialog(parent)
AutoRecoveryDialog::AutoRecoveryDialog(const QString &message,
const QStringList &recoveries,
bool autocheck_latest, QWidget *parent)
: QDialog(parent)
{
Init(message);
@@ -65,14 +68,18 @@ void AutoRecoveryDialog::Init(const QString& header_text)
tree_widget_->setHeaderHidden(true);
layout->addWidget(tree_widget_);
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
QDialogButtonBox *buttons =
new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttons->button(QDialogButtonBox::Ok)->setText(tr("Load"));
connect(buttons, &QDialogButtonBox::accepted, this, &AutoRecoveryDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &AutoRecoveryDialog::reject);
connect(buttons, &QDialogButtonBox::accepted, this,
&AutoRecoveryDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this,
&AutoRecoveryDialog::reject);
layout->addWidget(buttons);
}
void AutoRecoveryDialog::PopulateTree(const QStringList& recoveries, bool autocheck_latest)
void AutoRecoveryDialog::PopulateTree(const QStringList &recoveries,
bool autocheck_latest)
{
// Each entry in `recoveries` is a directory with 1+ recovery projects in it
QDir autorecovery_root(FileFunctions::GetAutoRecoveryRoot());
@@ -83,7 +90,8 @@ void AutoRecoveryDialog::PopulateTree(const QStringList& recoveries, bool autoch
QString pretty_name;
{
// Retrieve pretty name
QFile pretty_name_file(recovery_dir.filePath(QStringLiteral("realname.txt")));
QFile pretty_name_file(
recovery_dir.filePath(QStringLiteral("realname.txt")));
if (pretty_name_file.open(QFile::ReadOnly)) {
// Read pretty name that we should have written in the autorecovery process
pretty_name = QString::fromUtf8(pretty_name_file.readAll());
@@ -101,30 +109,41 @@ void AutoRecoveryDialog::PopulateTree(const QStringList& recoveries, bool autoch
{
// Populate with recoveries
QStringList entries = recovery_dir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed);
QStringList entries =
recovery_dir.entryList(QDir::Files | QDir::NoDotAndDotDot,
QDir::Name | QDir::Reversed);
for (int i = 0; i < entries.size(); i++) {
const QString &entry = entries.at(i);
if (entry.endsWith(QStringLiteral(".ove"), Qt::CaseInsensitive)) {
QTreeWidgetItem* entry_item = new QTreeWidgetItem(top_level);
if (entry.endsWith(QStringLiteral(".ove"),
Qt::CaseInsensitive)) {
QTreeWidgetItem *entry_item =
new QTreeWidgetItem(top_level);
bool ok;
qint64 recovery_time = entry.left(entry.indexOf('.')).toLongLong(&ok);
qint64 recovery_time =
entry.left(entry.indexOf('.')).toLongLong(&ok);
QString entry_name;
if (ok) {
// Set as time/date of recovery
entry_name = QDateTime::fromSecsSinceEpoch(recovery_time).toString();
entry_name =
QDateTime::fromSecsSinceEpoch(recovery_time)
.toString();
} else {
// Fallback if we couldn't discern a date from this
entry_name = entry;
}
entry_item->setText(0, entry_name);
entry_item->setData(0, kFilenameRole, recovery_dir.filePath(entry));
entry_item->setData(0, kFilenameRole,
recovery_dir.filePath(entry));
// Allow to be checked, auto-checking the first entry
entry_item->setCheckState(0, (autocheck_latest && top_level->childCount() == 1) ? Qt::Checked : Qt::Unchecked);
entry_item->setCheckState(
0, (autocheck_latest && top_level->childCount() == 1) ?
Qt::Checked :
Qt::Unchecked);
checkable_items_.append(entry_item);
}
+6 -8
View File
@@ -26,13 +26,14 @@
#include "common/define.h"
namespace olive {
class AutoRecoveryDialog : public QDialog
namespace olive
{
class AutoRecoveryDialog : public QDialog {
Q_OBJECT
public:
AutoRecoveryDialog(const QString& message, const QStringList& recoveries, bool autocheck_latest, QWidget* parent);
AutoRecoveryDialog(const QString &message, const QStringList &recoveries,
bool autocheck_latest, QWidget *parent);
public slots:
virtual void accept() override;
@@ -46,10 +47,7 @@ private:
QVector<QTreeWidgetItem *> checkable_items_;
enum DataRole {
kFilenameRole = Qt::UserRole
};
enum DataRole { kFilenameRole = Qt::UserRole };
};
}
+52 -33
View File
@@ -26,11 +26,13 @@
#include "common/qtutils.h"
namespace olive {
namespace olive
{
ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start, QWidget *parent) :
QDialog(parent),
color_manager_(color_manager)
ColorDialog::ColorDialog(ColorManager *color_manager, const ManagedColor &start,
QWidget *parent)
: QDialog(parent)
, color_manager_(color_manager)
{
setWindowTitle(tr("Select Color"));
@@ -52,7 +54,8 @@ ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start,
wheel_layout->addWidget(color_wheel_);
hsv_value_gradient_ = new ColorGradientWidget(Qt::Vertical);
hsv_value_gradient_->setFixedWidth(QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral("HHH")));
hsv_value_gradient_->setFixedWidth(
QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral("HHH")));
wheel_layout->addWidget(hsv_value_gradient_);
QHBoxLayout *swatch_layout = new QHBoxLayout();
@@ -82,29 +85,44 @@ ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start,
// Split window 50/50
splitter->setSizes({ INT_MAX, INT_MAX });
connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged, color_values_widget_, &ColorValuesWidget::SetColor);
connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged, hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor);
connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged, swatch_, &ColorSwatchChooser::SetCurrentColor);
connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged, color_values_widget_, &ColorValuesWidget::SetColor);
connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged, color_wheel_, &ColorWheelWidget::SetSelectedColor);
connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged, swatch_, &ColorSwatchChooser::SetCurrentColor);
connect(color_values_widget_, &ColorValuesWidget::ColorChanged, hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor);
connect(color_values_widget_, &ColorValuesWidget::ColorChanged, color_wheel_, &ColorWheelWidget::SetSelectedColor);
connect(color_values_widget_, &ColorValuesWidget::ColorChanged, swatch_, &ColorSwatchChooser::SetCurrentColor);
connect(swatch_, &ColorSwatchChooser::ColorClicked, hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor);
connect(swatch_, &ColorSwatchChooser::ColorClicked, color_wheel_, &ColorWheelWidget::SetSelectedColor);
connect(swatch_, &ColorSwatchChooser::ColorClicked, color_values_widget_, &ColorValuesWidget::SetColor);
connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged,
color_values_widget_, &ColorValuesWidget::SetColor);
connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged,
hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor);
connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged, swatch_,
&ColorSwatchChooser::SetCurrentColor);
connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged,
color_values_widget_, &ColorValuesWidget::SetColor);
connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged,
color_wheel_, &ColorWheelWidget::SetSelectedColor);
connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged,
swatch_, &ColorSwatchChooser::SetCurrentColor);
connect(color_values_widget_, &ColorValuesWidget::ColorChanged,
hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor);
connect(color_values_widget_, &ColorValuesWidget::ColorChanged,
color_wheel_, &ColorWheelWidget::SetSelectedColor);
connect(color_values_widget_, &ColorValuesWidget::ColorChanged, swatch_,
&ColorSwatchChooser::SetCurrentColor);
connect(swatch_, &ColorSwatchChooser::ColorClicked, hsv_value_gradient_,
&ColorGradientWidget::SetSelectedColor);
connect(swatch_, &ColorSwatchChooser::ColorClicked, color_wheel_,
&ColorWheelWidget::SetSelectedColor);
connect(swatch_, &ColorSwatchChooser::ColorClicked, color_values_widget_,
&ColorValuesWidget::SetColor);
connect(color_wheel_, &ColorWheelWidget::DiameterChanged, hsv_value_gradient_, &ColorGradientWidget::setFixedHeight);
connect(color_wheel_, &ColorWheelWidget::DiameterChanged,
hsv_value_gradient_, &ColorGradientWidget::setFixedHeight);
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
QDialogButtonBox *buttons =
new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
layout->addWidget(buttons);
SetColor(start);
connect(chooser_, &ColorSpaceChooser::ColorSpaceChanged, this, &ColorDialog::ColorSpaceChanged);
connect(chooser_, &ColorSpaceChooser::ColorSpaceChanged, this,
&ColorDialog::ColorSpaceChanged);
ColorSpaceChanged(chooser_->input(), chooser_->output());
// Set default size ratio to 2:1
@@ -119,18 +137,15 @@ void ColorDialog::SetColor(const ManagedColor &start)
Color managed_start;
if (start.color_input().isEmpty()) {
managed_start = start;
} else {
// Convert reference color to the input space
ColorProcessorPtr linear_to_input = ColorProcessor::Create(color_manager_,
color_manager_->GetReferenceColorSpace(),
ColorProcessorPtr linear_to_input = ColorProcessor::Create(
color_manager_, color_manager_->GetReferenceColorSpace(),
start.color_input());
managed_start = linear_to_input->ConvertColor(start);
}
color_wheel_->SetSelectedColor(managed_start);
@@ -164,15 +179,17 @@ ColorTransform ColorDialog::GetColorSpaceOutput() const
return chooser_->output();
}
void ColorDialog::ColorSpaceChanged(const QString &input, const ColorTransform &output)
void ColorDialog::ColorSpaceChanged(const QString &input,
const ColorTransform &output)
{
input_to_ref_processor_ = ColorProcessor::Create(color_manager_, input, color_manager_->GetReferenceColorSpace());
input_to_ref_processor_ = ColorProcessor::Create(
color_manager_, input, color_manager_->GetReferenceColorSpace());
ColorProcessorPtr ref_to_display = ColorProcessor::Create(color_manager_,
color_manager_->GetReferenceColorSpace(),
output);
ColorProcessorPtr ref_to_display = ColorProcessor::Create(
color_manager_, color_manager_->GetReferenceColorSpace(), output);
ColorProcessorPtr ref_to_input = ColorProcessor::Create(color_manager_, color_manager_->GetReferenceColorSpace(), input);
ColorProcessorPtr ref_to_input = ColorProcessor::Create(
color_manager_, color_manager_->GetReferenceColorSpace(), input);
// FIXME: For some reason, using OCIO::TRANSFORM_DIR_INVERSE (wrapped by ColorProcessor::kInverse) causes OCIO to
// crash. We've disabled that functionality for now (also disabling display_tab_ in ColorValuesWidget)
@@ -185,8 +202,10 @@ void ColorDialog::ColorSpaceChanged(const QString &input, const ColorTransform &
ColorProcessor::kInverse);*/
color_wheel_->SetColorProcessor(input_to_ref_processor_, ref_to_display);
hsv_value_gradient_->SetColorProcessor(input_to_ref_processor_, ref_to_display);
color_values_widget_->SetColorProcessor(input_to_ref_processor_, ref_to_display, nullptr, ref_to_input);
hsv_value_gradient_->SetColorProcessor(input_to_ref_processor_,
ref_to_display);
color_values_widget_->SetColorProcessor(
input_to_ref_processor_, ref_to_display, nullptr, ref_to_input);
}
}
+6 -5
View File
@@ -31,10 +31,10 @@
#include "widget/colorwheel/colorvalueswidget.h"
#include "widget/colorwheel/colorwheelwidget.h"
namespace olive {
class ColorDialog : public QDialog
namespace olive
{
class ColorDialog : public QDialog {
Q_OBJECT
public:
/**
@@ -56,7 +56,9 @@ public:
*
* QWidget parent.
*/
ColorDialog(ColorManager* color_manager, const ManagedColor &start = Color(1.0f, 1.0f, 1.0f), QWidget* parent = nullptr);
ColorDialog(ColorManager *color_manager,
const ManagedColor &start = Color(1.0f, 1.0f, 1.0f),
QWidget *parent = nullptr);
/**
* @brief Retrieves the color selected by the user
@@ -89,7 +91,6 @@ private:
private slots:
void ColorSpaceChanged(const QString &input, const ColorTransform &output);
};
}
+12 -10
View File
@@ -26,10 +26,11 @@
#include "core.h"
namespace olive {
namespace olive
{
ConfigDialogBase::ConfigDialogBase(QWidget* parent) :
QDialog(parent)
ConfigDialogBase::ConfigDialogBase(QWidget *parent)
: QDialog(parent)
{
QVBoxLayout *layout = new QVBoxLayout(this);
@@ -46,17 +47,18 @@ ConfigDialogBase::ConfigDialogBase(QWidget* parent) :
QDialogButtonBox *button_box = new QDialogButtonBox(this);
button_box->setOrientation(Qt::Horizontal);
button_box->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
button_box->setStandardButtons(QDialogButtonBox::Cancel |
QDialogButtonBox::Ok);
layout->addWidget(button_box);
connect(button_box, &QDialogButtonBox::accepted, this, &ConfigDialogBase::accept);
connect(button_box, &QDialogButtonBox::rejected, this, &ConfigDialogBase::reject);
connect(button_box, &QDialogButtonBox::accepted, this,
&ConfigDialogBase::accept);
connect(button_box, &QDialogButtonBox::rejected, this,
&ConfigDialogBase::reject);
connect(list_widget_,
&QListWidget::currentRowChanged,
preference_pane_stack_,
&QStackedWidget::setCurrentIndex);
connect(list_widget_, &QListWidget::currentRowChanged,
preference_pane_stack_, &QStackedWidget::setCurrentIndex);
}
void ConfigDialogBase::accept()
+6 -5
View File
@@ -27,10 +27,10 @@
#include "configdialogbasetab.h"
namespace olive {
class ConfigDialogBase : public QDialog
namespace olive
{
class ConfigDialogBase : public QDialog {
Q_OBJECT
public:
ConfigDialogBase(QWidget *parent = nullptr);
@@ -44,7 +44,9 @@ private slots:
protected:
void AddTab(ConfigDialogBaseTab *tab, const QString &title);
virtual void AcceptEvent(){}
virtual void AcceptEvent()
{
}
private:
QListWidget *list_widget_;
@@ -52,7 +54,6 @@ private:
QStackedWidget *preference_pane_stack_;
QList<ConfigDialogBaseTab *> tabs_;
};
}
@@ -20,7 +20,8 @@
#include "configdialogbasetab.h"
namespace olive {
namespace olive
{
bool ConfigDialogBaseTab::Validate()
{
+3 -3
View File
@@ -26,10 +26,10 @@
#include "config/config.h"
#include "undo/undocommand.h"
namespace olive {
class ConfigDialogBaseTab : public QWidget
namespace olive
{
class ConfigDialogBaseTab : public QWidget {
public:
ConfigDialogBaseTab() = default;
+36 -21
View File
@@ -28,17 +28,19 @@
#include "config/config.h"
#include "core.h"
namespace olive {
namespace olive
{
DiskCacheDialog::DiskCacheDialog(DiskCacheFolder *folder, QWidget* parent) :
QDialog(parent),
folder_(folder)
DiskCacheDialog::DiskCacheDialog(DiskCacheFolder *folder, QWidget *parent)
: QDialog(parent)
, folder_(folder)
{
QGridLayout *layout = new QGridLayout(this);
int row = 0;
layout->addWidget(new QLabel(tr("Disk Cache: %1").arg(folder->GetPath())), row, 0, 1, 2);
layout->addWidget(new QLabel(tr("Disk Cache: %1").arg(folder->GetPath())),
row, 0, 1, 2);
setWindowTitle(tr("Disk Cache Settings"));
row++;
@@ -48,32 +50,40 @@ DiskCacheDialog::DiskCacheDialog(DiskCacheFolder *folder, QWidget* parent) :
maximum_cache_slider_ = new FloatSlider();
maximum_cache_slider_->SetFormat(tr("%1 GB"));
maximum_cache_slider_->SetMinimum(1.0);
maximum_cache_slider_->SetValue(static_cast<double>(folder->GetLimit()) / static_cast<double>(kBytesInGigabyte));
maximum_cache_slider_->SetValue(static_cast<double>(folder->GetLimit()) /
static_cast<double>(kBytesInGigabyte));
layout->addWidget(maximum_cache_slider_, row, 1);
row++;
clear_cache_btn_ = new QPushButton(tr("Clear Disk Cache"));
connect(clear_cache_btn_, &QPushButton::clicked, this, static_cast<void(DiskCacheDialog::*)()>(&DiskCacheDialog::ClearDiskCache));
connect(clear_cache_btn_, &QPushButton::clicked, this,
static_cast<void (DiskCacheDialog::*)()>(
&DiskCacheDialog::ClearDiskCache));
layout->addWidget(clear_cache_btn_, row, 1);
row++;
clear_disk_cache_ = new QCheckBox(tr("Automatically clear disk cache on close"));
clear_disk_cache_ =
new QCheckBox(tr("Automatically clear disk cache on close"));
clear_disk_cache_->setChecked(folder->GetClearOnClose());
layout->addWidget(clear_disk_cache_, row, 1);
row++;
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttons, &QDialogButtonBox::accepted, this, &DiskCacheDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &DiskCacheDialog::reject);
QDialogButtonBox *buttons =
new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttons, &QDialogButtonBox::accepted, this,
&DiskCacheDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this,
&DiskCacheDialog::reject);
layout->addWidget(buttons, row, 0, 1, 2);
}
void DiskCacheDialog::accept()
{
qint64 new_disk_cache_limit = qRound64(maximum_cache_slider_->GetValue() * kBytesInGigabyte);
qint64 new_disk_cache_limit =
qRound64(maximum_cache_slider_->GetValue() * kBytesInGigabyte);
if (new_disk_cache_limit != folder_->GetLimit()) {
folder_->SetLimit(new_disk_cache_limit);
}
@@ -90,22 +100,27 @@ void DiskCacheDialog::ClearDiskCache()
ClearDiskCache(folder_->GetPath(), this, clear_cache_btn_);
}
void DiskCacheDialog::ClearDiskCache(const QString &path, QWidget *parent, QPushButton *clear_btn)
void DiskCacheDialog::ClearDiskCache(const QString &path, QWidget *parent,
QPushButton *clear_btn)
{
if (QMessageBox::question(parent,
tr("Clear Disk Cache"),
tr("Are you sure you want to clear the disk cache in '%1'?").arg(path),
if (QMessageBox::question(
parent, tr("Clear Disk Cache"),
tr("Are you sure you want to clear the disk cache in '%1'?")
.arg(path),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
if (clear_btn) clear_btn->setEnabled(false);
if (clear_btn)
clear_btn->setEnabled(false);
if (DiskManager::instance()->ClearDiskCache(path)) {
if (clear_btn) clear_btn->setText(tr("Disk Cache Cleared"));
if (clear_btn)
clear_btn->setText(tr("Disk Cache Cleared"));
} else {
QMessageBox::information(parent,
tr("Clear Disk Cache"),
QMessageBox::information(
parent, tr("Clear Disk Cache"),
tr("Disk cache failed to fully clear. You may have to delete the cache files manually."),
QMessageBox::Ok);
if (clear_btn) clear_btn->setText(tr("Disk Cache Partially Cleared"));
if (clear_btn)
clear_btn->setText(tr("Disk Cache Partially Cleared"));
}
}
}
+5 -5
View File
@@ -28,15 +28,16 @@
#include "render/diskmanager.h"
#include "widget/slider/floatslider.h"
namespace olive {
class DiskCacheDialog : public QDialog
namespace olive
{
class DiskCacheDialog : public QDialog {
Q_OBJECT
public:
DiskCacheDialog(DiskCacheFolder *folder, QWidget *parent = nullptr);
static void ClearDiskCache(const QString &path, QWidget *parent, QPushButton *clear_btn = nullptr);
static void ClearDiskCache(const QString &path, QWidget *parent,
QPushButton *clear_btn = nullptr);
public slots:
virtual void accept() override;
@@ -52,7 +53,6 @@ private:
private slots:
void ClearDiskCache();
};
}
+27 -21
View File
@@ -28,15 +28,16 @@
#include "common/qtutils.h"
#include "widget/slider/integerslider.h"
namespace olive {
namespace olive
{
AV1Section::AV1Section(QWidget *parent) :
AV1Section(AV1CRFSection::kDefaultAV1CRF, parent)
AV1Section::AV1Section(QWidget *parent)
: AV1Section(AV1CRFSection::kDefaultAV1CRF, parent)
{
}
AV1Section::AV1Section(int default_crf, QWidget *parent) :
CodecSection(parent)
AV1Section::AV1Section(int default_crf, QWidget *parent)
: CodecSection(parent)
{
QGridLayout *layout = new QGridLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
@@ -45,7 +46,8 @@ AV1Section::AV1Section(int default_crf, QWidget *parent) :
layout->addWidget(new QLabel(tr("Preset:")), row, 0);
preset_combobox_ = new QComboBox();
preset_combobox_->setToolTip(tr("This parameter governs the efficiency/encode-time trade-off.\n"
preset_combobox_->setToolTip(tr(
"This parameter governs the efficiency/encode-time trade-off.\n"
"Lower presets will result in an output with better quality for a given file size, but will take longer to encode.\n"
"Higher presets can result in a very fast encode, but will make some compromises on visual quality for a given crf value."));
@@ -61,7 +63,8 @@ AV1Section::AV1Section(int default_crf, QWidget *parent) :
layout->addWidget(new QLabel(tr("Compression Method:")), row, 0);
QComboBox *compression_box = new QComboBox();
compression_box->setToolTip(tr("This parameter governs the quality/size trade-off.\n"
compression_box->setToolTip(tr(
"This parameter governs the quality/size trade-off.\n"
"Higher CRF values will result in a final output that takes less space, but begins to lose detail.\n"
"Lower CRF values retain more detail at the cost of larger file sizes.\n"
"The possible range of CRF in SVT-AV1 is 1-63."));
@@ -79,29 +82,29 @@ AV1Section::AV1Section(int default_crf, QWidget *parent) :
crf_section_ = new AV1CRFSection(default_crf);
compression_method_stack_->addWidget(crf_section_);
connect(compression_box,
connect(
compression_box,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
compression_method_stack_,
&QStackedWidget::setCurrentIndex);
compression_method_stack_, &QStackedWidget::setCurrentIndex);
}
void AV1Section::AddOpts(EncodingParams *params)
{
CompressionMethod method = static_cast<CompressionMethod>(compression_method_stack_->currentIndex());
CompressionMethod method = static_cast<CompressionMethod>(
compression_method_stack_->currentIndex());
if (method == kConstantRateFactor) {
// Set Quantizer value
params->set_video_option(QStringLiteral("qp"), QString::number(crf_section_->GetValue()));
params->set_video_option(QStringLiteral("qp"),
QString::number(crf_section_->GetValue()));
}
params->set_video_option(QStringLiteral("preset"), QString::number(preset_combobox_->currentIndex()));
params->set_video_option(QStringLiteral("preset"),
QString::number(preset_combobox_->currentIndex()));
}
AV1CRFSection::AV1CRFSection(int default_crf, QWidget *parent) :
QWidget(parent)
AV1CRFSection::AV1CRFSection(int default_crf, QWidget *parent)
: QWidget(parent)
{
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
@@ -113,15 +116,18 @@ AV1CRFSection::AV1CRFSection(int default_crf, QWidget *parent) :
layout->addWidget(crf_slider_);
IntegerSlider *crf_input = new IntegerSlider();
crf_input->setMaximumWidth(QtUtils::QFontMetricsWidth(crf_input->fontMetrics(), QStringLiteral("HHHH")));
crf_input->setMaximumWidth(QtUtils::QFontMetricsWidth(
crf_input->fontMetrics(), QStringLiteral("HHHH")));
crf_input->SetMinimum(kMinimumCRF);
crf_input->SetMaximum(kMaximumCRF);
crf_input->SetValue(default_crf);
crf_input->SetDefaultValue(default_crf);
layout->addWidget(crf_input);
connect(crf_slider_, &QSlider::valueChanged, crf_input, &IntegerSlider::SetValue);
connect(crf_input, &IntegerSlider::ValueChanged, crf_slider_, &QSlider::setValue);
connect(crf_slider_, &QSlider::valueChanged, crf_input,
&IntegerSlider::SetValue);
connect(crf_input, &IntegerSlider::ValueChanged, crf_slider_,
&QSlider::setValue);
}
int AV1CRFSection::GetValue() const
+4 -6
View File
@@ -28,10 +28,10 @@
#include "codecsection.h"
#include "widget/slider/floatslider.h"
namespace olive {
class AV1CRFSection : public QWidget
namespace olive
{
class AV1CRFSection : public QWidget {
Q_OBJECT
public:
AV1CRFSection(int default_crf, QWidget *parent = nullptr);
@@ -45,11 +45,9 @@ private:
static const int kMaximumCRF = 63;
QSlider *crf_slider_;
};
class AV1Section : public CodecSection
{
class AV1Section : public CodecSection {
Q_OBJECT
public:
enum CompressionMethod {
+9 -5
View File
@@ -23,10 +23,11 @@
#include <QGridLayout>
#include <QLabel>
namespace olive {
namespace olive
{
CineformSection::CineformSection(QWidget *parent) :
CodecSection(parent)
CineformSection::CineformSection(QWidget *parent)
: CodecSection(parent)
{
QGridLayout *layout = new QGridLayout(this);
@@ -79,12 +80,15 @@ CineformSection::CineformSection(QWidget *parent) :
void CineformSection::AddOpts(EncodingParams *params)
{
params->set_video_option(QStringLiteral("quality"), QString::number(quality_combobox_->currentIndex()));
params->set_video_option(
QStringLiteral("quality"),
QString::number(quality_combobox_->currentIndex()));
}
void CineformSection::SetOpts(const EncodingParams *p)
{
quality_combobox_->setCurrentIndex(p->video_option(QStringLiteral("quality")).toInt());
quality_combobox_->setCurrentIndex(
p->video_option(QStringLiteral("quality")).toInt());
}
}
+3 -4
View File
@@ -25,10 +25,10 @@
#include "codecsection.h"
namespace olive {
class CineformSection : public CodecSection
namespace olive
{
class CineformSection : public CodecSection {
Q_OBJECT
public:
CineformSection(QWidget *parent = nullptr);
@@ -39,7 +39,6 @@ public:
private:
QComboBox *quality_combobox_;
};
}
+4 -3
View File
@@ -20,10 +20,11 @@
#include "codecsection.h"
namespace olive {
namespace olive
{
CodecSection::CodecSection(QWidget *parent) :
QWidget(parent)
CodecSection::CodecSection(QWidget *parent)
: QWidget(parent)
{
}
+11 -6
View File
@@ -25,18 +25,23 @@
#include "codec/encoder.h"
namespace olive {
class CodecSection : public QWidget
namespace olive
{
class CodecSection : public QWidget {
Q_OBJECT
public:
CodecSection(QWidget *parent = nullptr);
virtual void AddOpts(EncodingParams* params){Q_UNUSED(params)}
virtual void SetOpts(const EncodingParams *p){Q_UNUSED(p)}
virtual void AddOpts(EncodingParams *params)
{
Q_UNUSED(params)
}
virtual void SetOpts(const EncodingParams *p)
{
Q_UNUSED(p)
}
};
}
+6 -3
View File
@@ -20,7 +20,8 @@
#include "codecstack.h"
namespace olive {
namespace olive
{
#define super QStackedWidget
@@ -41,9 +42,11 @@ void CodecStack::OnChange(int index)
{
for (int i = 0; i < count(); i++) {
if (i == index) {
widget(i)->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
widget(i)->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
} else {
widget(i)->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
widget(i)->setSizePolicy(QSizePolicy::Ignored,
QSizePolicy::Ignored);
}
widget(i)->adjustSize();
}

Some files were not shown because too many files have changed in this diff Show More