Merge branch 'master' into av1
This commit is contained in:
@@ -67,10 +67,26 @@ jobs:
|
||||
if: github.event_name == 'push'
|
||||
continue-on-error: true
|
||||
|
||||
- name: Build Core Library
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}
|
||||
run: |
|
||||
git clone https://github.com/olive-editor/core
|
||||
cd core
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} -G "${{ matrix.cmake-gen }}" \
|
||||
-DCMAKE_C_COMPILER="${{ matrix.cc-compiler }}" \
|
||||
-DCMAKE_CXX_COMPILER="${{ matrix.cxx-compiler }}" \
|
||||
-DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/core/install" \
|
||||
$CMAKE_ARGS
|
||||
ninja install
|
||||
|
||||
- name: Configure CMake
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
PATH=$GITHUB_WORKSPACE/core/install:$PATH
|
||||
cmake .. -G "${{ matrix.cmake-gen }}" \
|
||||
-DCMAKE_BUILD_TYPE="${{ matrix.build-type }}" \
|
||||
-DCMAKE_C_COMPILER="${{ matrix.cc-compiler }}" \
|
||||
@@ -202,10 +218,25 @@ jobs:
|
||||
if: github.event_name == 'push'
|
||||
continue-on-error: true
|
||||
|
||||
- name: Build Core Library
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}
|
||||
run: |
|
||||
git clone https://github.com/olive-editor/core
|
||||
cd core
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} -G "${{ matrix.cmake-gen }}" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \
|
||||
-DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/core/install" \
|
||||
$CMAKE_ARGS
|
||||
ninja install
|
||||
|
||||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/build
|
||||
run: |
|
||||
PATH=$GITHUB_WORKSPACE/core/install:$PATH
|
||||
cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} -G "${{ matrix.cmake-gen }}" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \
|
||||
$CMAKE_ARGS
|
||||
@@ -353,11 +384,27 @@ jobs:
|
||||
brew update
|
||||
brew install ninja
|
||||
|
||||
- name: Build Core Library
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}
|
||||
run: |
|
||||
git clone https://github.com/olive-editor/core
|
||||
cd core
|
||||
mkdir build
|
||||
cd build
|
||||
PATH=$DEP_LOCATION:$DEP_LOCATION/bin:$DEP_LOCATION/include:$DEP_LOCATION/lib:$DEP_LOCATION/crashpad:$PATH \
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${{ matrix.min-deploy }} -G "${{ matrix.cmake-gen }}" \
|
||||
-DCMAKE_OSX_ARCHITECTURES="${{ matrix.os-arch }}" \
|
||||
-DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/core/install" \
|
||||
$CMAKE_ARGS
|
||||
ninja install
|
||||
|
||||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/build
|
||||
run: |
|
||||
PATH=$DEP_LOCATION:$DEP_LOCATION/bin:$DEP_LOCATION/include:$DEP_LOCATION/lib:$DEP_LOCATION/crashpad:$PATH \
|
||||
PATH=$DEP_LOCATION:$DEP_LOCATION/bin:$DEP_LOCATION/include:$DEP_LOCATION/lib:$DEP_LOCATION/crashpad:$GITHUB_WORKSPACE/core/install:$PATH \
|
||||
cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${{ matrix.min-deploy }} -G "${{ matrix.cmake-gen }}" \
|
||||
-DCMAKE_OSX_ARCHITECTURES="${{ matrix.os-arch }}" \
|
||||
|
||||
@@ -94,6 +94,14 @@ find_package(OpenEXR REQUIRED)
|
||||
list(APPEND OLIVE_LIBRARIES ${OPENEXR_LIBRARIES})
|
||||
list(APPEND OLIVE_INCLUDE_DIRS ${OPENEXR_INCLUDES})
|
||||
|
||||
# Link Olive
|
||||
find_package(Olive REQUIRED
|
||||
COMPONENTS
|
||||
Core
|
||||
)
|
||||
list(APPEND OLIVE_LIBRARIES ${LIBOLIVE_LIBRARIES})
|
||||
list(APPEND OLIVE_INCLUDE_DIRS ${LIBOLIVE_INCLUDE_DIRS})
|
||||
|
||||
# Link Qt
|
||||
set(QT_LIBRARIES
|
||||
Core
|
||||
|
||||
+16
-16
@@ -73,7 +73,7 @@ int InputCallback(const void *input, void *output, unsigned long frameCount, con
|
||||
FFmpegEncoder *f = static_cast<FFmpegEncoder*>(userData);
|
||||
|
||||
AudioParams our_params = f->params().audio_params();
|
||||
our_params.set_format(AudioParams::GetPackedEquivalent(f->params().audio_params().format()));
|
||||
our_params.set_format(f->params().audio_params().format().to_packed_equivalent());
|
||||
|
||||
f->WriteAudioData(our_params, reinterpret_cast<const uint8_t**>(&input), frameCount);
|
||||
|
||||
@@ -119,27 +119,27 @@ void AudioManager::ClearBufferedOutput()
|
||||
output_buffer_->clear();
|
||||
}
|
||||
|
||||
PaSampleFormat AudioManager::GetPortAudioSampleFormat(AudioParams::Format fmt)
|
||||
PaSampleFormat AudioManager::GetPortAudioSampleFormat(SampleFormat fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case AudioParams::kFormatUnsigned8Packed:
|
||||
case AudioParams::kFormatUnsigned8Planar:
|
||||
case SampleFormat::U8:
|
||||
case SampleFormat::U8P:
|
||||
return paUInt8;
|
||||
case AudioParams::kFormatSigned16Packed:
|
||||
case AudioParams::kFormatSigned16Planar:
|
||||
case SampleFormat::S16:
|
||||
case SampleFormat::S16P:
|
||||
return paInt16;
|
||||
case AudioParams::kFormatSigned32Packed:
|
||||
case AudioParams::kFormatSigned32Planar:
|
||||
case SampleFormat::S32:
|
||||
case SampleFormat::S32P:
|
||||
return paInt32;
|
||||
case AudioParams::kFormatFloat32Packed:
|
||||
case AudioParams::kFormatFloat32Planar:
|
||||
case SampleFormat::F32:
|
||||
case SampleFormat::F32P:
|
||||
return paFloat32;
|
||||
case AudioParams::kFormatSigned64Packed:
|
||||
case AudioParams::kFormatSigned64Planar:
|
||||
case AudioParams::kFormatFloat64Packed:
|
||||
case AudioParams::kFormatFloat64Planar:
|
||||
case AudioParams::kFormatInvalid:
|
||||
case AudioParams::kFormatCount:
|
||||
case SampleFormat::S64:
|
||||
case SampleFormat::S64P:
|
||||
case SampleFormat::F64:
|
||||
case SampleFormat::F64P:
|
||||
case SampleFormat::INVALID:
|
||||
case SampleFormat::COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "audio/audioprocessor.h"
|
||||
#include "common/define.h"
|
||||
#include "codec/ffmpeg/ffmpegencoder.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/audioplaybackcache.h"
|
||||
#include "render/previewaudiodevice.h"
|
||||
|
||||
@@ -94,7 +93,7 @@ private:
|
||||
|
||||
virtual ~AudioManager() override;
|
||||
|
||||
static PaSampleFormat GetPortAudioSampleFormat(AudioParams::Format fmt);
|
||||
static PaSampleFormat GetPortAudioSampleFormat(SampleFormat fmt);
|
||||
|
||||
void CloseOutputStream();
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ extern "C" {
|
||||
#include <libavfilter/buffersink.h>
|
||||
}
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "common/ffmpegutils.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -88,13 +90,13 @@ bool AudioProcessor::Open(const AudioParams &from, const AudioParams &to, double
|
||||
double speed_log = log(tempo) / log(base);
|
||||
|
||||
// This is the number of how many 0.5 or 2.0 tempos we need to daisychain
|
||||
int whole = qFloor(speed_log);
|
||||
int whole = std::floor(speed_log);
|
||||
|
||||
// Set speed_log to the remainder
|
||||
speed_log -= whole;
|
||||
|
||||
for (int i=0;i<=whole;i++) {
|
||||
double filter_tempo = (i == whole) ? qPow(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
|
||||
@@ -115,7 +117,7 @@ bool AudioProcessor::Open(const AudioParams &from, const AudioParams &to, double
|
||||
|
||||
// Create conversion filter
|
||||
if (from.sample_rate() != to.sample_rate() || from.channel_layout() != to.channel_layout() || from.format() != to.format()
|
||||
|| (to.FormatIsPlanar() && create_tempo)) { // Tempo processor automatically converts to packed,
|
||||
|| (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,
|
||||
@@ -236,7 +238,7 @@ int AudioProcessor::Convert(float **in, int nb_in_samples, AudioProcessor::Buffe
|
||||
if (output) {
|
||||
int nb_channels = to_.channel_count();
|
||||
|
||||
if (to_.FormatIsPacked()) {
|
||||
if (to_.format().is_packed()) {
|
||||
nb_channels = 1;
|
||||
}
|
||||
|
||||
@@ -259,7 +261,7 @@ int AudioProcessor::Convert(float **in, int nb_in_samples, AudioProcessor::Buffe
|
||||
}
|
||||
|
||||
int nb_bytes = out_frame_->nb_samples * to_.bytes_per_sample_per_channel();
|
||||
if (to_.FormatIsPacked()) {
|
||||
if (to_.format().is_packed()) {
|
||||
nb_bytes *= to_.channel_count();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,15 +22,19 @@
|
||||
#define AUDIOPROCESSOR_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <olive/core/core.h>
|
||||
#include <QByteArray>
|
||||
|
||||
extern "C" {
|
||||
#include <libavfilter/avfilter.h>
|
||||
}
|
||||
|
||||
#include "render/audioparams.h"
|
||||
#include "common/define.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
using namespace core;
|
||||
|
||||
class AudioProcessor
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <QtGlobal>
|
||||
|
||||
#include "config/config.h"
|
||||
#include "common/cpuoptimize.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -459,8 +458,8 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
|
||||
break;
|
||||
}
|
||||
|
||||
next_sample_index = qMin(arr.size(),
|
||||
start_sample_index + qFloor(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),
|
||||
@@ -480,7 +479,7 @@ size_t AudioVisualWaveform::time_to_samples(const rational &time, double sample_
|
||||
|
||||
size_t AudioVisualWaveform::time_to_samples(const double &time, double sample_rate) const
|
||||
{
|
||||
return qFloor(time * sample_rate) * channels_;
|
||||
return std::floor(time * sample_rate) * channels_;
|
||||
}
|
||||
|
||||
std::map<rational, AudioVisualWaveform::Sample>::const_iterator AudioVisualWaveform::GetMipmapForScale(double scale) const
|
||||
|
||||
@@ -21,13 +21,14 @@
|
||||
#ifndef SUMSAMPLES_H
|
||||
#define SUMSAMPLES_H
|
||||
|
||||
#include <olive/core/core.h>
|
||||
#include <QPainter>
|
||||
#include <QVector>
|
||||
|
||||
#include "codec/samplebuffer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
using namespace core;
|
||||
|
||||
/**
|
||||
* @brief A buffer of data used to store a visual representation of audio
|
||||
*
|
||||
|
||||
@@ -33,7 +33,5 @@ set(OLIVE_SOURCES
|
||||
codec/frame.h
|
||||
codec/planarfiledevice.cpp
|
||||
codec/planarfiledevice.h
|
||||
codec/samplebuffer.cpp
|
||||
codec/samplebuffer.h
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QHash>
|
||||
|
||||
#include "codec/ffmpeg/ffmpegdecoder.h"
|
||||
#include "codec/planarfiledevice.h"
|
||||
#include "codec/oiio/oiiodecoder.h"
|
||||
#include "common/ffmpegutils.h"
|
||||
#include "common/filefunctions.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "conformmanager.h"
|
||||
#include "node/project/project.h"
|
||||
#include "task/taskmanager.h"
|
||||
@@ -338,7 +338,7 @@ 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -31,11 +31,10 @@ extern "C" {
|
||||
#include <QWaitCondition>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "codec/samplebuffer.h"
|
||||
#include "common/rational.h"
|
||||
#include "node/block/block.h"
|
||||
#include "node/project/footage/footagedescription.h"
|
||||
#include "render/cancelatom.h"
|
||||
#include "render/rendermodes.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -160,7 +159,7 @@ public:
|
||||
Renderer *renderer = nullptr;
|
||||
rational time;
|
||||
int divider = 1;
|
||||
VideoParams::Format maximum_format = VideoParams::kFormatInvalid;
|
||||
PixelFormat maximum_format = PixelFormat::INVALID;
|
||||
CancelAtom *cancelled = nullptr;
|
||||
VideoParams::ColorRange force_range = VideoParams::kColorRangeDefault;
|
||||
VideoParams::Interlacing src_interlacing = VideoParams::kInterlaceNone;
|
||||
|
||||
+13
-14
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "common/xmlutils.h"
|
||||
#include "ffmpeg/ffmpegencoder.h"
|
||||
#include "oiio/oiioencoder.h"
|
||||
@@ -202,8 +201,8 @@ void EncodingParams::Save(QXmlStreamWriter *writer) const
|
||||
writer->writeTextElement(QStringLiteral("format"), QString::number(format_));
|
||||
|
||||
writer->writeTextElement(QStringLiteral("range"), QString::number(has_custom_range_));
|
||||
writer->writeTextElement(QStringLiteral("customrangein"), custom_range_.in().toString());
|
||||
writer->writeTextElement(QStringLiteral("customrangeout"), custom_range_.out().toString());
|
||||
writer->writeTextElement(QStringLiteral("customrangein"), QString::fromStdString(custom_range_.in().toString()));
|
||||
writer->writeTextElement(QStringLiteral("customrangeout"), QString::fromStdString(custom_range_.out().toString()));
|
||||
|
||||
writer->writeStartElement(QStringLiteral("video"));
|
||||
|
||||
@@ -214,8 +213,8 @@ void EncodingParams::Save(QXmlStreamWriter *writer) const
|
||||
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"), video_params_.pixel_aspect_ratio().toString());
|
||||
writer->writeTextElement(QStringLiteral("timebase"), video_params_.time_base().toString());
|
||||
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_));
|
||||
@@ -258,7 +257,7 @@ void EncodingParams::Save(QXmlStreamWriter *writer) const
|
||||
writer->writeTextElement(QStringLiteral("codec"), QString::number(audio_codec_));
|
||||
writer->writeTextElement(QStringLiteral("samplerate"), QString::number(audio_params_.sample_rate()));
|
||||
writer->writeTextElement(QStringLiteral("channellayout"), QString::number(audio_params_.channel_layout()));
|
||||
writer->writeTextElement(QStringLiteral("format"), QString::number(audio_params_.format()));
|
||||
writer->writeTextElement(QStringLiteral("format"), QString::fromStdString(audio_params_.format().to_string()));
|
||||
writer->writeTextElement(QStringLiteral("bitrate"), QString::number(audio_bit_rate_));
|
||||
}
|
||||
|
||||
@@ -338,9 +337,9 @@ QStringList Encoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
std::vector<AudioParams::Format> Encoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
|
||||
std::vector<SampleFormat> Encoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
|
||||
{
|
||||
return std::vector<AudioParams::Format>();
|
||||
return std::vector<SampleFormat>();
|
||||
}
|
||||
|
||||
QMatrix4x4 EncodingParams::GenerateMatrix(EncodingParams::VideoScalingMethod method,
|
||||
@@ -381,9 +380,9 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
|
||||
} 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());
|
||||
custom_range_in = rational::fromString(reader->readElementText().toStdString());
|
||||
} else if (reader->name() == QStringLiteral("customrangeout")) {
|
||||
custom_range_out = rational::fromString(reader->readElementText());
|
||||
custom_range_out = rational::fromString(reader->readElementText().toStdString());
|
||||
} else if (reader->name() == QStringLiteral("video")) {
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("enabled")) {
|
||||
@@ -399,11 +398,11 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
|
||||
} 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<VideoParams::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()));
|
||||
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()));
|
||||
video_params_.set_time_base(rational::fromString(reader->readElementText().toStdString()));
|
||||
} else if (reader->name() == QStringLiteral("divider")) {
|
||||
video_params_.set_divider(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("bitrate")) {
|
||||
@@ -472,7 +471,7 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
|
||||
} else if (reader->name() == QStringLiteral("channellayout")) {
|
||||
audio_params_.set_channel_layout(reader->readElementText().toULongLong());
|
||||
} else if (reader->name() == QStringLiteral("format")) {
|
||||
audio_params_.set_format(static_cast<AudioParams::Format>(reader->readElementText().toInt()));
|
||||
audio_params_.set_format(SampleFormat::from_string(reader->readElementText().toStdString()));
|
||||
} else if (reader->name() == QStringLiteral("bitrate")) {
|
||||
audio_bit_rate_ = reader->readElementText().toLongLong();
|
||||
} else {
|
||||
|
||||
+4
-7
@@ -29,10 +29,7 @@
|
||||
#include "codec/exportcodec.h"
|
||||
#include "codec/exportformat.h"
|
||||
#include "codec/frame.h"
|
||||
#include "codec/samplebuffer.h"
|
||||
#include "common/timerange.h"
|
||||
#include "node/block/subtitle/subtitle.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/colortransform.h"
|
||||
#include "render/subtitleparams.h"
|
||||
#include "render/videoparams.h"
|
||||
@@ -205,13 +202,13 @@ public:
|
||||
static Encoder *CreateFromParams(const EncodingParams ¶ms);
|
||||
|
||||
virtual QStringList GetPixelFormatsForCodec(ExportCodec::Codec c) const;
|
||||
virtual std::vector<AudioParams::Format> GetSampleFormatsForCodec(ExportCodec::Codec c) const;
|
||||
virtual std::vector<SampleFormat> GetSampleFormatsForCodec(ExportCodec::Codec c) const;
|
||||
|
||||
const EncodingParams& params() const;
|
||||
|
||||
virtual VideoParams::Format GetDesiredPixelFormat() const
|
||||
virtual PixelFormat GetDesiredPixelFormat() const
|
||||
{
|
||||
return VideoParams::kFormatInvalid;
|
||||
return PixelFormat::INVALID;
|
||||
}
|
||||
|
||||
const QString& GetError() const
|
||||
@@ -232,7 +229,7 @@ public:
|
||||
public slots:
|
||||
virtual bool Open() = 0;
|
||||
|
||||
virtual bool WriteFrame(olive::FramePtr frame, olive::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;
|
||||
|
||||
|
||||
@@ -218,9 +218,9 @@ QStringList ExportFormat::GetPixelFormatsForCodec(ExportFormat::Format f, Export
|
||||
return list;
|
||||
}
|
||||
|
||||
std::vector<AudioParams::Format> ExportFormat::GetSampleFormatsForCodec(Format format, ExportCodec::Codec c)
|
||||
std::vector<SampleFormat> ExportFormat::GetSampleFormatsForCodec(Format format, ExportCodec::Codec c)
|
||||
{
|
||||
std::vector<AudioParams::Format> f;
|
||||
std::vector<SampleFormat> f;
|
||||
Encoder *e = Encoder::CreateFromFormat(format, EncodingParams());
|
||||
|
||||
if (e) {
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "common/define.h"
|
||||
#include "exportcodec.h"
|
||||
#include "render/audioparams.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -62,7 +61,7 @@ public:
|
||||
static QList<ExportCodec::Codec> GetSubtitleCodecs(ExportFormat::Format f);
|
||||
|
||||
static QStringList GetPixelFormatsForCodec(Format f, ExportCodec::Codec c);
|
||||
static std::vector<AudioParams::Format> GetSampleFormatsForCodec(Format f, ExportCodec::Codec c);
|
||||
static std::vector<SampleFormat> GetSampleFormatsForCodec(Format f, ExportCodec::Codec c);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ extern "C" {
|
||||
#include "codec/planarfiledevice.h"
|
||||
#include "common/ffmpegutils.h"
|
||||
#include "common/filefunctions.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "render/renderer.h"
|
||||
#include "render/subtitleparams.h"
|
||||
|
||||
@@ -78,7 +77,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f, const RetrieveVi
|
||||
{
|
||||
// Determine native format
|
||||
AVPixelFormat ideal_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(f->format));
|
||||
VideoParams::Format native_fmt = GetNativePixelFormat(ideal_fmt);
|
||||
PixelFormat native_fmt = GetNativePixelFormat(ideal_fmt);
|
||||
int native_channels = GetNativeChannelCount(ideal_fmt);
|
||||
|
||||
// Set up video params
|
||||
@@ -469,7 +468,7 @@ 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(AudioParams::kInternalFormat);
|
||||
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);
|
||||
@@ -642,17 +641,17 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector<QString> &filenames, cons
|
||||
return success;
|
||||
}
|
||||
|
||||
VideoParams::Format FFmpegDecoder::GetNativePixelFormat(AVPixelFormat pix_fmt)
|
||||
PixelFormat FFmpegDecoder::GetNativePixelFormat(AVPixelFormat pix_fmt)
|
||||
{
|
||||
switch (pix_fmt) {
|
||||
case AV_PIX_FMT_RGB24:
|
||||
case AV_PIX_FMT_RGBA:
|
||||
return VideoParams::kFormatUnsigned8;
|
||||
return PixelFormat::U8;
|
||||
case AV_PIX_FMT_RGB48:
|
||||
case AV_PIX_FMT_RGBA64:
|
||||
return VideoParams::kFormatUnsigned16;
|
||||
return PixelFormat::U16;
|
||||
default:
|
||||
return VideoParams::kFormatInvalid;
|
||||
return PixelFormat::INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ private:
|
||||
|
||||
void FreeScaler();
|
||||
|
||||
static VideoParams::Format GetNativePixelFormat(AVPixelFormat pix_fmt);
|
||||
static PixelFormat GetNativePixelFormat(AVPixelFormat pix_fmt);
|
||||
static int GetNativeChannelCount(AVPixelFormat pix_fmt);
|
||||
|
||||
static uint64_t ValidateChannelLayout(AVStream *stream);
|
||||
|
||||
@@ -29,7 +29,6 @@ extern "C" {
|
||||
#include <QFile>
|
||||
|
||||
#include "common/ffmpegutils.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -53,7 +52,7 @@ QStringList FFmpegEncoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const
|
||||
{
|
||||
QStringList pix_fmts;
|
||||
|
||||
const AVCodec* codec_info = GetEncoder(c, AudioParams::kFormatInvalid);
|
||||
const AVCodec* codec_info = GetEncoder(c, SampleFormat::INVALID);
|
||||
|
||||
if (codec_info) {
|
||||
for (int i=0; codec_info->pix_fmts[i]!=-1; i++) {
|
||||
@@ -70,29 +69,29 @@ QStringList FFmpegEncoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const
|
||||
return pix_fmts;
|
||||
}
|
||||
|
||||
std::vector<AudioParams::Format> FFmpegEncoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
|
||||
std::vector<SampleFormat> FFmpegEncoder::GetSampleFormatsForCodec(ExportCodec::Codec c) const
|
||||
{
|
||||
std::vector<AudioParams::Format> f;
|
||||
std::vector<SampleFormat> f;
|
||||
|
||||
if (c == ExportCodec::kCodecPCM) {
|
||||
// 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 FFmpeg)
|
||||
// (because first element is the "default" in tFFmpeg)
|
||||
f = {
|
||||
AudioParams::kFormatSigned16Packed,
|
||||
AudioParams::kFormatUnsigned8Packed,
|
||||
AudioParams::kFormatSigned32Packed,
|
||||
AudioParams::kFormatSigned64Packed,
|
||||
AudioParams::kFormatFloat32Packed,
|
||||
AudioParams::kFormatFloat64Packed
|
||||
SampleFormat::S16,
|
||||
SampleFormat::U8,
|
||||
SampleFormat::S32,
|
||||
SampleFormat::S64,
|
||||
SampleFormat::F32,
|
||||
SampleFormat::F64
|
||||
};
|
||||
} else {
|
||||
const AVCodec* codec_info = GetEncoder(c, AudioParams::kFormatInvalid);
|
||||
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++) {
|
||||
AudioParams::Format this_format = FFmpegUtils::GetNativeSampleFormat(static_cast<AVSampleFormat>(codec_info->sample_fmts[i]));
|
||||
if (this_format != AudioParams::kFormatInvalid) {
|
||||
SampleFormat this_format = FFmpegUtils::GetNativeSampleFormat(static_cast<AVSampleFormat>(codec_info->sample_fmts[i]));
|
||||
if (this_format != SampleFormat::INVALID) {
|
||||
f.push_back(this_format);
|
||||
}
|
||||
}
|
||||
@@ -130,7 +129,7 @@ bool FFmpegEncoder::Open()
|
||||
}
|
||||
|
||||
// This is the format we will expect frames received in Write() to be in
|
||||
VideoParams::Format native_pixel_fmt = params().video_params().format();
|
||||
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);
|
||||
@@ -882,7 +881,7 @@ bool FFmpegEncoder::InitializeResampleContext(const AudioParams &audio)
|
||||
return true;
|
||||
}
|
||||
|
||||
const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c, AudioParams::Format aformat)
|
||||
const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c, SampleFormat aformat)
|
||||
{
|
||||
switch (c) {
|
||||
case ExportCodec::kCodecH264:
|
||||
@@ -919,26 +918,26 @@ const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c, AudioParams::Form
|
||||
return avcodec_find_encoder(AV_CODEC_ID_AAC);
|
||||
case ExportCodec::kCodecPCM:
|
||||
switch (aformat) {
|
||||
case AudioParams::kFormatInvalid:
|
||||
case AudioParams::kFormatCount:
|
||||
case AudioParams::kFormatUnsigned8Planar:
|
||||
case AudioParams::kFormatSigned16Planar:
|
||||
case AudioParams::kFormatSigned32Planar:
|
||||
case AudioParams::kFormatSigned64Planar:
|
||||
case AudioParams::kFormatFloat32Planar:
|
||||
case AudioParams::kFormatFloat64Planar:
|
||||
case SampleFormat::INVALID:
|
||||
case SampleFormat::COUNT:
|
||||
case SampleFormat::U8P:
|
||||
case SampleFormat::S16P:
|
||||
case SampleFormat::S32P:
|
||||
case SampleFormat::S64P:
|
||||
case SampleFormat::F32P:
|
||||
case SampleFormat::F64P:
|
||||
break;
|
||||
case AudioParams::kFormatUnsigned8Packed:
|
||||
case SampleFormat::U8:
|
||||
return avcodec_find_encoder(AV_CODEC_ID_PCM_U8);
|
||||
case AudioParams::kFormatSigned16Packed:
|
||||
case SampleFormat::S16:
|
||||
return avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE);
|
||||
case AudioParams::kFormatSigned32Packed:
|
||||
case SampleFormat::S32:
|
||||
return avcodec_find_encoder(AV_CODEC_ID_PCM_S32LE);
|
||||
case AudioParams::kFormatSigned64Packed:
|
||||
case SampleFormat::S64:
|
||||
return avcodec_find_encoder(AV_CODEC_ID_PCM_S64LE);
|
||||
case AudioParams::kFormatFloat32Packed:
|
||||
case SampleFormat::F32:
|
||||
return avcodec_find_encoder(AV_CODEC_ID_PCM_F32LE);
|
||||
case AudioParams::kFormatFloat64Packed:
|
||||
case SampleFormat::F64:
|
||||
return avcodec_find_encoder(AV_CODEC_ID_PCM_F64LE);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -41,11 +41,11 @@ public:
|
||||
|
||||
virtual QStringList GetPixelFormatsForCodec(ExportCodec::Codec c) const override;
|
||||
|
||||
virtual std::vector<AudioParams::Format> 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::rational time) override;
|
||||
virtual bool WriteFrame(olive::FramePtr frame, olive::core::rational time) override;
|
||||
|
||||
virtual bool WriteAudio(const olive::SampleBuffer &audio) override;
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
|
||||
virtual void Close() override;
|
||||
|
||||
virtual VideoParams::Format GetDesiredPixelFormat() const override
|
||||
virtual PixelFormat GetDesiredPixelFormat() const override
|
||||
{
|
||||
return video_conversion_fmt_;
|
||||
}
|
||||
@@ -82,7 +82,7 @@ private:
|
||||
|
||||
bool InitializeResampleContext(const AudioParams &audio);
|
||||
|
||||
static const AVCodec *GetEncoder(ExportCodec::Codec c, AudioParams::Format aformat);
|
||||
static const AVCodec *GetEncoder(ExportCodec::Codec c, SampleFormat aformat);
|
||||
|
||||
AVFormatContext* fmt_ctx_;
|
||||
|
||||
@@ -91,7 +91,7 @@ private:
|
||||
AVFilterGraph *video_scale_ctx_;
|
||||
AVFilterContext *video_buffersrc_ctx_;
|
||||
AVFilterContext *video_buffersink_ctx_;
|
||||
VideoParams::Format video_conversion_fmt_;
|
||||
PixelFormat video_conversion_fmt_;
|
||||
|
||||
AVStream* audio_stream_;
|
||||
AVCodecContext* audio_codec_ctx_;
|
||||
|
||||
+2
-2
@@ -84,7 +84,7 @@ FramePtr Frame::Interlace(FramePtr top, FramePtr bottom)
|
||||
return interlaced;
|
||||
}
|
||||
|
||||
int Frame::generate_linesize_bytes(int width, VideoParams::Format 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);
|
||||
@@ -146,7 +146,7 @@ void Frame::destroy()
|
||||
}
|
||||
}
|
||||
|
||||
FramePtr Frame::convert(VideoParams::Format format) const
|
||||
FramePtr Frame::convert(PixelFormat format) const
|
||||
{
|
||||
// Create new params with destination format
|
||||
VideoParams params = params_;
|
||||
|
||||
+4
-5
@@ -22,11 +22,10 @@
|
||||
#define FRAME_H
|
||||
|
||||
#include <memory>
|
||||
#include <olive/core/core.h>
|
||||
#include <QVector>
|
||||
|
||||
#include "common/define.h"
|
||||
#include "common/rational.h"
|
||||
#include "render/color.h"
|
||||
#include "render/videoparams.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -53,7 +52,7 @@ public:
|
||||
|
||||
static FramePtr Interlace(FramePtr top, FramePtr bottom);
|
||||
|
||||
static int generate_linesize_bytes(int width, VideoParams::Format format, int channel_count);
|
||||
static int generate_linesize_bytes(int width, PixelFormat format, int channel_count);
|
||||
|
||||
int linesize_pixels() const
|
||||
{
|
||||
@@ -75,7 +74,7 @@ public:
|
||||
return params_.effective_height();
|
||||
}
|
||||
|
||||
VideoParams::Format format() const
|
||||
PixelFormat format() const
|
||||
{
|
||||
return params_.format();
|
||||
}
|
||||
@@ -152,7 +151,7 @@ public:
|
||||
return data_size_;
|
||||
}
|
||||
|
||||
FramePtr convert(VideoParams::Format format) const;
|
||||
FramePtr convert(PixelFormat format) const;
|
||||
|
||||
private:
|
||||
VideoParams params_;
|
||||
|
||||
@@ -205,7 +205,7 @@ bool OIIODecoder::OpenImageHandler(const QString &fn, int subimage)
|
||||
// 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));
|
||||
|
||||
if (pix_fmt_ == VideoParams::kFormatInvalid) {
|
||||
if (pix_fmt_ == PixelFormat::INVALID) {
|
||||
qWarning() << "Failed to convert OIIO::ImageDesc to native pixel format";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ private:
|
||||
|
||||
static VideoParams GetVideoParamsFromImageSpec(const OIIO::ImageSpec &spec);
|
||||
|
||||
VideoParams::Format pix_fmt_;
|
||||
PixelFormat pix_fmt_;
|
||||
OIIO::TypeDesc::BASETYPE oiio_pix_fmt_;
|
||||
|
||||
Frame buffer_;
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
public slots:
|
||||
virtual bool Open() override;
|
||||
|
||||
virtual bool WriteFrame(olive::FramePtr frame, olive::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;
|
||||
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
#ifndef PLANARFILEDEVICE_H
|
||||
#define PLANARFILEDEVICE_H
|
||||
|
||||
#include <olive/core/core.h>
|
||||
#include <QFile>
|
||||
#include <QObject>
|
||||
|
||||
#include "codec/samplebuffer.h"
|
||||
#include "common/define.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
using namespace core;
|
||||
|
||||
class PlanarFileDevice : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "samplebuffer.h"
|
||||
|
||||
#include "common/cpuoptimize.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
SampleBuffer::SampleBuffer() :
|
||||
sample_count_per_channel_(0)
|
||||
{
|
||||
}
|
||||
|
||||
SampleBuffer::SampleBuffer(const AudioParams &audio_params, const rational &length) :
|
||||
audio_params_(audio_params)
|
||||
{
|
||||
sample_count_per_channel_ = audio_params_.time_to_samples(length);
|
||||
allocate();
|
||||
}
|
||||
|
||||
SampleBuffer::SampleBuffer(const AudioParams &audio_params, size_t samples_per_channel) :
|
||||
audio_params_(audio_params),
|
||||
sample_count_per_channel_(samples_per_channel)
|
||||
{
|
||||
allocate();
|
||||
}
|
||||
|
||||
const AudioParams &SampleBuffer::audio_params() const
|
||||
{
|
||||
return audio_params_;
|
||||
}
|
||||
|
||||
void SampleBuffer::set_audio_params(const AudioParams ¶ms)
|
||||
{
|
||||
if (is_allocated()) {
|
||||
qWarning() << "Tried to set parameters on allocated sample buffer";
|
||||
return;
|
||||
}
|
||||
|
||||
audio_params_ = params;
|
||||
}
|
||||
|
||||
void SampleBuffer::set_sample_count(const size_t &sample_count)
|
||||
{
|
||||
if (is_allocated()) {
|
||||
qWarning() << "Tried to set sample count on allocated sample buffer";
|
||||
return;
|
||||
}
|
||||
|
||||
sample_count_per_channel_ = sample_count;
|
||||
}
|
||||
|
||||
void SampleBuffer::allocate()
|
||||
{
|
||||
if (!audio_params_.is_valid()) {
|
||||
qWarning() << "Tried to allocate sample buffer with invalid audio parameters";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sample_count_per_channel_) {
|
||||
qWarning() << "Tried to allocate sample buffer with zero sample count";
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_allocated()) {
|
||||
qWarning() << "Tried to allocate already allocated sample buffer";
|
||||
return;
|
||||
}
|
||||
|
||||
data_.resize(audio_params_.channel_count());
|
||||
for (int i=0; i<audio_params_.channel_count(); i++) {
|
||||
data_[i].resize(sample_count_per_channel_);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleBuffer::destroy()
|
||||
{
|
||||
data_.clear();
|
||||
}
|
||||
|
||||
void SampleBuffer::reverse()
|
||||
{
|
||||
if (!is_allocated()) {
|
||||
qWarning() << "Tried to reverse an unallocated sample buffer";
|
||||
return;
|
||||
}
|
||||
|
||||
size_t half_nb_sample = sample_count_per_channel_ / 2;
|
||||
|
||||
for (size_t i=0;i<half_nb_sample;i++) {
|
||||
size_t opposite_ind = sample_count_per_channel_ - i - 1;
|
||||
|
||||
for (int j=0;j<audio_params_.channel_count();j++) {
|
||||
std::swap(data_[j][i], data_[j][opposite_ind]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SampleBuffer::speed(double speed)
|
||||
{
|
||||
if (!is_allocated()) {
|
||||
qWarning() << "Tried to speed an unallocated sample buffer";
|
||||
return;
|
||||
}
|
||||
|
||||
sample_count_per_channel_ = qRound(static_cast<double>(sample_count_per_channel_) / speed);
|
||||
|
||||
std::vector< std::vector<float> > output_data;
|
||||
|
||||
output_data.resize(audio_params_.channel_count());
|
||||
for (int i=0; i<audio_params_.channel_count(); i++) {
|
||||
output_data[i].resize(sample_count_per_channel_);
|
||||
}
|
||||
|
||||
for (size_t i=0;i<sample_count_per_channel_;i++) {
|
||||
size_t input_index = qFloor(static_cast<double>(i) * speed);
|
||||
|
||||
for (int j=0;j<audio_params_.channel_count();j++) {
|
||||
output_data[j][i] = data_[j][input_index];
|
||||
}
|
||||
}
|
||||
|
||||
data_ = output_data;
|
||||
}
|
||||
|
||||
void SampleBuffer::transform_volume(float f)
|
||||
{
|
||||
for (int i=0;i<audio_params().channel_count();i++) {
|
||||
transform_volume_for_channel(i, f);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleBuffer::transform_volume_for_channel(int channel, float volume)
|
||||
{
|
||||
float *cdat = data_[channel].data();
|
||||
size_t unopt_start = 0;
|
||||
|
||||
#if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM)
|
||||
__m128 mult = _mm_load1_ps(&volume);
|
||||
unopt_start = (sample_count_per_channel_ / 4) * 4;
|
||||
for (size_t j=0; j<unopt_start; j+=4) {
|
||||
float *here = cdat + j;
|
||||
__m128 samples = _mm_loadu_ps(here);
|
||||
__m128 multiplied = _mm_mul_ps(samples, mult);
|
||||
_mm_storeu_ps(here, multiplied);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t j=unopt_start; j<sample_count_per_channel_; j++) {
|
||||
cdat[j] *= volume;
|
||||
}
|
||||
}
|
||||
|
||||
void SampleBuffer::transform_volume_for_sample(size_t sample_index, float volume)
|
||||
{
|
||||
for (int i=0;i<audio_params().channel_count();i++) {
|
||||
transform_volume_for_sample_on_channel(sample_index, i, volume);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleBuffer::transform_volume_for_sample_on_channel(size_t sample_index, int channel, float volume)
|
||||
{
|
||||
data_[channel][sample_index] *= volume;
|
||||
}
|
||||
|
||||
void SampleBuffer::clamp()
|
||||
{
|
||||
for (int i=0; i<channel_count(); i++) {
|
||||
clamp_channel(i);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleBuffer::silence()
|
||||
{
|
||||
silence(0, sample_count_per_channel_);
|
||||
}
|
||||
|
||||
void SampleBuffer::silence(size_t start_sample, size_t end_sample)
|
||||
{
|
||||
silence_bytes(start_sample * sizeof(float), end_sample * sizeof(float));
|
||||
}
|
||||
|
||||
void SampleBuffer::silence_bytes(size_t start_byte, size_t end_byte)
|
||||
{
|
||||
if (!is_allocated()) {
|
||||
qWarning() << "Tried to fill an unallocated sample buffer";
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0;i<audio_params().channel_count();i++) {
|
||||
memset(reinterpret_cast<char*>(data_[i].data()) + start_byte, 0, end_byte - start_byte);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleBuffer::set(int channel, const float *data, size_t sample_offset, size_t sample_length)
|
||||
{
|
||||
if (!is_allocated()) {
|
||||
qWarning() << "Tried to fill an unallocated sample buffer";
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&data_[channel].data()[sample_offset], data, sizeof(float) * sample_length);
|
||||
}
|
||||
|
||||
void SampleBuffer::clamp_channel(int channel)
|
||||
{
|
||||
const float min = -1.0f;
|
||||
const float max = 1.0f;
|
||||
|
||||
float *cdat = data_[channel].data();
|
||||
size_t unopt_start = 0;
|
||||
|
||||
#if defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_ARM)
|
||||
__m128 min_sse = _mm_load1_ps(&min);
|
||||
__m128 max_sse = _mm_load1_ps(&max);
|
||||
|
||||
unopt_start = (sample_count_per_channel_ / 4) * 4;
|
||||
for (size_t j=0; j<unopt_start; j+=4) {
|
||||
float *here = cdat + j;
|
||||
__m128 samples = _mm_loadu_ps(here);
|
||||
|
||||
samples = _mm_max_ps(samples, min_sse);
|
||||
samples = _mm_min_ps(samples, max_sse);
|
||||
|
||||
_mm_storeu_ps(here, samples);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t sample=unopt_start; sample<sample_count(); sample++) {
|
||||
float &s = data(channel)[sample];
|
||||
s = std::clamp(s, min, max);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef SAMPLEBUFFER_H
|
||||
#define SAMPLEBUFFER_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "render/audioparams.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
/**
|
||||
* @brief A buffer of audio samples
|
||||
*
|
||||
* Audio samples in this structure are always stored in PLANAR (separated by channel). This is done to simplify audio
|
||||
* rendering code. This replaces the old system of using QByteArrays (containing packed audio) and while SampleBuffer
|
||||
* replaces many of those in the rendering/processing side of things, QByteArrays are currently still in use for
|
||||
* playback, including reading to and from the cache.
|
||||
*/
|
||||
class SampleBuffer
|
||||
{
|
||||
public:
|
||||
SampleBuffer();
|
||||
SampleBuffer(const AudioParams& audio_params, const rational& length);
|
||||
SampleBuffer(const AudioParams& audio_params, size_t samples_per_channel);
|
||||
|
||||
const AudioParams& audio_params() const;
|
||||
void set_audio_params(const AudioParams& params);
|
||||
|
||||
const size_t &sample_count() const { return sample_count_per_channel_; }
|
||||
void set_sample_count(const size_t &sample_count);
|
||||
void set_sample_count(const rational &length)
|
||||
{
|
||||
set_sample_count(audio_params_.time_to_samples(length));
|
||||
}
|
||||
|
||||
float* data(int channel)
|
||||
{
|
||||
return data_[channel].data();
|
||||
}
|
||||
|
||||
const float* data(int channel) const
|
||||
{
|
||||
return data_.at(channel).data();
|
||||
}
|
||||
|
||||
std::vector<float *> to_raw_ptrs()
|
||||
{
|
||||
std::vector<float *> r(data_.size());
|
||||
for (size_t i=0; i<r.size(); i++) {
|
||||
r[i] = data_[i].data();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int channel_count() const { return data_.size(); }
|
||||
|
||||
bool is_allocated() const { return !data_.empty(); }
|
||||
void allocate();
|
||||
void destroy();
|
||||
|
||||
void reverse();
|
||||
void speed(double speed);
|
||||
void transform_volume(float f);
|
||||
void transform_volume_for_channel(int channel, float volume);
|
||||
void transform_volume_for_sample(size_t sample_index, float volume);
|
||||
void transform_volume_for_sample_on_channel(size_t sample_index, int channel, float volume);
|
||||
|
||||
void clamp();
|
||||
|
||||
void silence();
|
||||
void silence(size_t start_sample, size_t end_sample);
|
||||
void silence_bytes(size_t start_byte, size_t end_byte);
|
||||
|
||||
void set(int channel, const float* data, size_t sample_offset, size_t sample_length);
|
||||
void set(int channel, const float* data, size_t sample_length)
|
||||
{
|
||||
set(channel, data, 0, sample_length);
|
||||
}
|
||||
|
||||
private:
|
||||
void clamp_channel(int channel);
|
||||
|
||||
AudioParams audio_params_;
|
||||
|
||||
size_t sample_count_per_channel_;
|
||||
|
||||
std::vector< std::vector<float> > data_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(olive::SampleBuffer)
|
||||
|
||||
#endif // SAMPLEBUFFER_H
|
||||
@@ -16,11 +16,8 @@
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
common/bezier.cpp
|
||||
common/bezier.h
|
||||
common/cancelableobject.h
|
||||
common/channellayout.h
|
||||
common/clamp.h
|
||||
common/commandlineparser.cpp
|
||||
common/commandlineparser.h
|
||||
common/crashpadinterface.cpp
|
||||
@@ -50,13 +47,7 @@ set(OLIVE_SOURCES
|
||||
common/range.h
|
||||
common/ratiodialog.cpp
|
||||
common/ratiodialog.h
|
||||
common/rational.cpp
|
||||
common/rational.h
|
||||
common/threadsafemap.h
|
||||
common/timecodefunctions.cpp
|
||||
common/timecodefunctions.h
|
||||
common/timerange.cpp
|
||||
common/timerange.h
|
||||
common/tohex.h
|
||||
common/util.h
|
||||
common/xmlutils.cpp
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "bezier.h"
|
||||
|
||||
#include <QtMath>
|
||||
|
||||
#include "common/clamp.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
Bezier::Bezier() :
|
||||
x_(0),
|
||||
y_(0),
|
||||
cp1_x_(0),
|
||||
cp1_y_(0),
|
||||
cp2_x_(0),
|
||||
cp2_y_(0)
|
||||
{
|
||||
}
|
||||
|
||||
Bezier::Bezier(double x, double y) :
|
||||
x_(x),
|
||||
y_(y),
|
||||
cp1_x_(0),
|
||||
cp1_y_(0),
|
||||
cp2_x_(0),
|
||||
cp2_y_(0)
|
||||
{
|
||||
}
|
||||
|
||||
Bezier::Bezier(double x, double y, double cp1_x, double cp1_y, double cp2_x, double cp2_y) :
|
||||
x_(x),
|
||||
y_(y),
|
||||
cp1_x_(cp1_x),
|
||||
cp1_y_(cp1_y),
|
||||
cp2_x_(cp2_x),
|
||||
cp2_y_(cp2_y)
|
||||
{
|
||||
}
|
||||
|
||||
double Bezier::QuadraticXtoT(double x, double a, double b, double c)
|
||||
{
|
||||
// Clamp to prevent infinite loop
|
||||
x = clamp(x, a, c);
|
||||
|
||||
return CalculateTFromX(false, x, a, b, c, 0);
|
||||
}
|
||||
|
||||
double Bezier::QuadraticTtoY(double a, double b, double c, double t)
|
||||
{
|
||||
return qPow(1.0 - t, 2)*a + 2*(1.0 - t)*t*b + qPow(t, 2)*c;
|
||||
}
|
||||
|
||||
double Bezier::CubicXtoT(double x, double a, double b, double c, double d)
|
||||
{
|
||||
// Clamp to prevent infinite loop
|
||||
x = clamp(x, a, d);
|
||||
|
||||
return CalculateTFromX(true, x, a, b, c, d);
|
||||
}
|
||||
|
||||
double Bezier::CubicTtoY(double a, double b, double c, double d, double t)
|
||||
{
|
||||
return qPow(1.0 - t, 3)*a + 3*qPow(1.0 - t, 2)*t*b + 3*(1.0 - t)*qPow(t, 2)*c + qPow(t, 3)*d;
|
||||
}
|
||||
|
||||
double Bezier::CalculateTFromX(bool cubic, double x, double a, double b, double c, double d)
|
||||
{
|
||||
double bottom = 0.0;
|
||||
double top = 1.0;
|
||||
|
||||
while (true) {
|
||||
if (bottom == top) {
|
||||
return bottom;
|
||||
}
|
||||
|
||||
double mid = (bottom + top) * 0.5;
|
||||
double test = cubic ? CubicTtoY(a, b, c, d, mid) : QuadraticTtoY(a, b, c, mid);
|
||||
|
||||
if (qAbs(test - x) < 0.000001) {
|
||||
return mid;
|
||||
} else if (x > test) {
|
||||
bottom = mid;
|
||||
} else {
|
||||
top = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return qSNaN();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef BEZIER_H
|
||||
#define BEZIER_H
|
||||
|
||||
#include <QPointF>
|
||||
#include <QObject>
|
||||
|
||||
#include "common/define.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class Bezier
|
||||
{
|
||||
public:
|
||||
Bezier();
|
||||
Bezier(double x, double y);
|
||||
Bezier(double x, double y, double cp1_x, double cp1_y, double cp2_x, double cp2_y);
|
||||
|
||||
const double &x() const {return x_; }
|
||||
const double &y() const {return y_; }
|
||||
const double &cp1_x() const { return cp1_x_; }
|
||||
const double &cp1_y() const { return cp1_y_; }
|
||||
const double &cp2_x() const { return cp2_x_; }
|
||||
const double &cp2_y() const { return cp2_y_; }
|
||||
|
||||
QPointF ToPointF() const
|
||||
{
|
||||
return QPointF(x_, y_);
|
||||
}
|
||||
|
||||
QPointF ControlPoint1ToPointF() const
|
||||
{
|
||||
return QPointF(cp1_x_, cp1_y_);
|
||||
}
|
||||
|
||||
QPointF ControlPoint2ToPointF() const
|
||||
{
|
||||
return QPointF(cp2_x_, cp2_y_);
|
||||
}
|
||||
|
||||
void set_x(const double &x) { x_ = x; }
|
||||
void set_y(const double &y) { y_ = y; }
|
||||
void set_cp1_x(const double &cp1_x) { cp1_x_ = cp1_x; }
|
||||
void set_cp1_y(const double &cp1_y) { cp1_y_ = cp1_y; }
|
||||
void set_cp2_x(const double &cp2_x) { cp2_x_ = cp2_x; }
|
||||
void set_cp2_y(const double &cp2_y) { cp2_y_ = cp2_y; }
|
||||
|
||||
static double QuadraticXtoT(double x, double a, double b, double c);
|
||||
|
||||
static double QuadraticTtoY(double a, double b, double c, double t);
|
||||
|
||||
static double QuadraticXtoY(double x, const QPointF &a, const QPointF &b, const QPointF &c)
|
||||
{
|
||||
return QuadraticTtoY(a.y(), b.y(), c.y(), QuadraticXtoT(x, a.x(), b.x(), c.x()));
|
||||
}
|
||||
|
||||
static double CubicXtoT(double x, double a, double b, double c, double d);
|
||||
|
||||
static double CubicTtoY(double a, double b, double c, double d, double t);
|
||||
|
||||
static double CubicXtoY(double x, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d)
|
||||
{
|
||||
return CubicTtoY(a.y(), b.y(), c.y(), d.y(), CubicXtoT(x, a.x(), b.x(), c.x(), d.x()));
|
||||
}
|
||||
|
||||
private:
|
||||
static double CalculateTFromX(bool cubic, double x, double a, double b, double c, double d);
|
||||
|
||||
double x_;
|
||||
double y_;
|
||||
|
||||
double cp1_x_;
|
||||
double cp1_y_;
|
||||
|
||||
double cp2_x_;
|
||||
double cp2_y_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(olive::Bezier)
|
||||
|
||||
#endif // BEZIER_H
|
||||
@@ -1,47 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef CLAMP_H
|
||||
#define CLAMP_H
|
||||
|
||||
template<typename T>
|
||||
/**
|
||||
* @brief Clamp a value between a minimum and a maximum value
|
||||
*
|
||||
* Similar to using min() and max() functions, but performs both at once. If value is less than minimum, this returns
|
||||
* minimum. If it is more than maximum, this returns maximum. Otherwise it returns value as-is.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* Will always return a value between minimum and maximum (inclusive).
|
||||
*/
|
||||
T clamp(T value, T minimum, T maximum) {
|
||||
if (value < minimum) {
|
||||
return minimum;
|
||||
}
|
||||
|
||||
if (value > maximum) {
|
||||
return maximum;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif // CLAMP_H
|
||||
+54
-54
@@ -22,13 +22,13 @@
|
||||
|
||||
namespace olive {
|
||||
|
||||
AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt, VideoParams::Format maximum)
|
||||
AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt, PixelFormat maximum)
|
||||
{
|
||||
AVPixelFormat possible_pix_fmts[3];
|
||||
|
||||
possible_pix_fmts[0] = AV_PIX_FMT_RGBA;
|
||||
|
||||
if (maximum == VideoParams::kFormatUnsigned8) {
|
||||
if (maximum == PixelFormat::U8) {
|
||||
possible_pix_fmts[1] = AV_PIX_FMT_NONE;
|
||||
} else {
|
||||
possible_pix_fmts[1] = AV_PIX_FMT_RGBA64;
|
||||
@@ -41,70 +41,70 @@ AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt
|
||||
nullptr);
|
||||
}
|
||||
|
||||
AudioParams::Format FFmpegUtils::GetNativeSampleFormat(const AVSampleFormat &smp_fmt)
|
||||
SampleFormat FFmpegUtils::GetNativeSampleFormat(const AVSampleFormat &smp_fmt)
|
||||
{
|
||||
switch (smp_fmt) {
|
||||
case AV_SAMPLE_FMT_U8:
|
||||
return AudioParams::kFormatUnsigned8Packed;
|
||||
return SampleFormat::U8;
|
||||
case AV_SAMPLE_FMT_S16:
|
||||
return AudioParams::kFormatSigned16Packed;
|
||||
return SampleFormat::S16;
|
||||
case AV_SAMPLE_FMT_S32:
|
||||
return AudioParams::kFormatSigned32Packed;
|
||||
return SampleFormat::S32;
|
||||
case AV_SAMPLE_FMT_S64:
|
||||
return AudioParams::kFormatSigned64Packed;
|
||||
return SampleFormat::S64;
|
||||
case AV_SAMPLE_FMT_FLT:
|
||||
return AudioParams::kFormatFloat32Packed;
|
||||
return SampleFormat::F32;
|
||||
case AV_SAMPLE_FMT_DBL:
|
||||
return AudioParams::kFormatFloat64Packed;
|
||||
return SampleFormat::F64;
|
||||
case AV_SAMPLE_FMT_U8P :
|
||||
return AudioParams::kFormatUnsigned8Planar;
|
||||
return SampleFormat::U8P;
|
||||
case AV_SAMPLE_FMT_S16P:
|
||||
return AudioParams::kFormatSigned16Planar;
|
||||
return SampleFormat::S16P;
|
||||
case AV_SAMPLE_FMT_S32P:
|
||||
return AudioParams::kFormatSigned32Planar;
|
||||
return SampleFormat::S32P;
|
||||
case AV_SAMPLE_FMT_S64P:
|
||||
return AudioParams::kFormatSigned64Planar;
|
||||
return SampleFormat::S64P;
|
||||
case AV_SAMPLE_FMT_FLTP:
|
||||
return AudioParams::kFormatFloat32Planar;
|
||||
return SampleFormat::F32P;
|
||||
case AV_SAMPLE_FMT_DBLP:
|
||||
return AudioParams::kFormatFloat64Planar;
|
||||
return SampleFormat::F64P;
|
||||
case AV_SAMPLE_FMT_NONE:
|
||||
case AV_SAMPLE_FMT_NB:
|
||||
break;
|
||||
}
|
||||
|
||||
return AudioParams::kFormatInvalid;
|
||||
return SampleFormat::INVALID;
|
||||
}
|
||||
|
||||
AVSampleFormat FFmpegUtils::GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt)
|
||||
AVSampleFormat FFmpegUtils::GetFFmpegSampleFormat(const SampleFormat &smp_fmt)
|
||||
{
|
||||
switch (smp_fmt) {
|
||||
case AudioParams::kFormatUnsigned8Packed:
|
||||
case SampleFormat::U8:
|
||||
return AV_SAMPLE_FMT_U8;
|
||||
case AudioParams::kFormatSigned16Packed:
|
||||
case SampleFormat::S16:
|
||||
return AV_SAMPLE_FMT_S16;
|
||||
case AudioParams::kFormatSigned32Packed:
|
||||
case SampleFormat::S32:
|
||||
return AV_SAMPLE_FMT_S32;
|
||||
case AudioParams::kFormatSigned64Packed:
|
||||
case SampleFormat::S64:
|
||||
return AV_SAMPLE_FMT_S64;
|
||||
case AudioParams::kFormatFloat32Packed:
|
||||
case SampleFormat::F32:
|
||||
return AV_SAMPLE_FMT_FLT;
|
||||
case AudioParams::kFormatFloat64Packed:
|
||||
case SampleFormat::F64:
|
||||
return AV_SAMPLE_FMT_DBL;
|
||||
case AudioParams::kFormatUnsigned8Planar:
|
||||
case SampleFormat::U8P:
|
||||
return AV_SAMPLE_FMT_U8P;
|
||||
case AudioParams::kFormatSigned16Planar:
|
||||
case SampleFormat::S16P:
|
||||
return AV_SAMPLE_FMT_S16P;
|
||||
case AudioParams::kFormatSigned32Planar:
|
||||
case SampleFormat::S32P:
|
||||
return AV_SAMPLE_FMT_S32P;
|
||||
case AudioParams::kFormatSigned64Planar:
|
||||
case SampleFormat::S64P:
|
||||
return AV_SAMPLE_FMT_S64P;
|
||||
case AudioParams::kFormatFloat32Planar:
|
||||
case SampleFormat::F32P:
|
||||
return AV_SAMPLE_FMT_FLTP;
|
||||
case AudioParams::kFormatFloat64Planar:
|
||||
case SampleFormat::F64P:
|
||||
return AV_SAMPLE_FMT_DBLP;
|
||||
case AudioParams::kFormatInvalid:
|
||||
case AudioParams::kFormatCount:
|
||||
case SampleFormat::INVALID:
|
||||
case SampleFormat::COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -148,30 +148,30 @@ AVPixelFormat FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AVPixelFormat f)
|
||||
return f;
|
||||
}
|
||||
|
||||
AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const VideoParams::Format &pix_fmt, int channel_layout)
|
||||
AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const PixelFormat &pix_fmt, int channel_layout)
|
||||
{
|
||||
if (channel_layout == VideoParams::kRGBChannelCount) {
|
||||
switch (pix_fmt) {
|
||||
case VideoParams::kFormatUnsigned8:
|
||||
case PixelFormat::U8:
|
||||
return AV_PIX_FMT_RGB24;
|
||||
case VideoParams::kFormatUnsigned16:
|
||||
case PixelFormat::U16:
|
||||
return AV_PIX_FMT_RGB48;
|
||||
case VideoParams::kFormatFloat16:
|
||||
case VideoParams::kFormatFloat32:
|
||||
case VideoParams::kFormatInvalid:
|
||||
case VideoParams::kFormatCount:
|
||||
case PixelFormat::F16:
|
||||
case PixelFormat::F32:
|
||||
case PixelFormat::INVALID:
|
||||
case PixelFormat::COUNT:
|
||||
break;
|
||||
}
|
||||
} else if (channel_layout == VideoParams::kRGBAChannelCount) {
|
||||
switch (pix_fmt) {
|
||||
case VideoParams::kFormatUnsigned8:
|
||||
case PixelFormat::U8:
|
||||
return AV_PIX_FMT_RGBA;
|
||||
case VideoParams::kFormatUnsigned16:
|
||||
case PixelFormat::U16:
|
||||
return AV_PIX_FMT_RGBA64;
|
||||
case VideoParams::kFormatFloat16:
|
||||
case VideoParams::kFormatFloat32:
|
||||
case VideoParams::kFormatInvalid:
|
||||
case VideoParams::kFormatCount:
|
||||
case PixelFormat::F16:
|
||||
case PixelFormat::F32:
|
||||
case PixelFormat::INVALID:
|
||||
case PixelFormat::COUNT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -179,21 +179,21 @@ AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const VideoParams::Format &pix_f
|
||||
return AV_PIX_FMT_NONE;
|
||||
}
|
||||
|
||||
VideoParams::Format FFmpegUtils::GetCompatiblePixelFormat(const VideoParams::Format &pix_fmt)
|
||||
PixelFormat FFmpegUtils::GetCompatiblePixelFormat(const PixelFormat &pix_fmt)
|
||||
{
|
||||
switch (pix_fmt) {
|
||||
case VideoParams::kFormatUnsigned8:
|
||||
return VideoParams::kFormatUnsigned8;
|
||||
case VideoParams::kFormatUnsigned16:
|
||||
case VideoParams::kFormatFloat16:
|
||||
case VideoParams::kFormatFloat32:
|
||||
return VideoParams::kFormatUnsigned16;
|
||||
case VideoParams::kFormatInvalid:
|
||||
case VideoParams::kFormatCount:
|
||||
case PixelFormat::U8:
|
||||
return PixelFormat::U8;
|
||||
case PixelFormat::U16:
|
||||
case PixelFormat::F16:
|
||||
case PixelFormat::F32:
|
||||
return PixelFormat::U16;
|
||||
case PixelFormat::INVALID:
|
||||
case PixelFormat::COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
return VideoParams::kFormatInvalid;
|
||||
return PixelFormat::INVALID;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,37 +27,40 @@ extern "C" {
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
#include "render/audioparams.h"
|
||||
#include <olive/core/core.h>
|
||||
|
||||
#include "render/videoparams.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
using namespace core;
|
||||
|
||||
class FFmpegUtils {
|
||||
public:
|
||||
/**
|
||||
* @brief Returns an AVPixelFormat that can be used to convert a frame to a data type Olive supports with minimal data loss
|
||||
*/
|
||||
static AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt, VideoParams::Format maximum = VideoParams::kFormatInvalid);
|
||||
static AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt, PixelFormat maximum = PixelFormat::INVALID);
|
||||
|
||||
/**
|
||||
* @brief Returns a native pixel format that can be used to convert from a native frame to an AVFrame with minimal data loss
|
||||
*/
|
||||
static VideoParams::Format GetCompatiblePixelFormat(const VideoParams::Format& pix_fmt);
|
||||
static PixelFormat GetCompatiblePixelFormat(const PixelFormat& pix_fmt);
|
||||
|
||||
/**
|
||||
* @brief Returns an FFmpeg pixel format for a given native pixel format
|
||||
*/
|
||||
static AVPixelFormat GetFFmpegPixelFormat(const VideoParams::Format& pix_fmt, int channel_layout);
|
||||
static AVPixelFormat GetFFmpegPixelFormat(const PixelFormat& pix_fmt, int channel_layout);
|
||||
|
||||
/**
|
||||
* @brief Returns a native sample format type for a given AVSampleFormat
|
||||
*/
|
||||
static AudioParams::Format GetNativeSampleFormat(const AVSampleFormat& smp_fmt);
|
||||
static SampleFormat GetNativeSampleFormat(const AVSampleFormat& smp_fmt);
|
||||
|
||||
/**
|
||||
* @brief Returns an FFmpeg sample format type for a given native type
|
||||
*/
|
||||
static AVSampleFormat GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt);
|
||||
static AVSampleFormat GetFFmpegSampleFormat(const SampleFormat &smp_fmt);
|
||||
|
||||
/**
|
||||
* @brief Returns an SWS_CS_* macro from an AVColorSpace enum member
|
||||
|
||||
@@ -22,22 +22,22 @@
|
||||
|
||||
namespace olive {
|
||||
|
||||
OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(VideoParams::Format format)
|
||||
OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(PixelFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case VideoParams::kFormatUnsigned8:
|
||||
case PixelFormat::U8:
|
||||
return OCIO::BIT_DEPTH_UINT8;
|
||||
case VideoParams::kFormatUnsigned16:
|
||||
case PixelFormat::U16:
|
||||
return OCIO::BIT_DEPTH_UINT16;
|
||||
break;
|
||||
case VideoParams::kFormatFloat16:
|
||||
case PixelFormat::F16:
|
||||
return OCIO::BIT_DEPTH_F16;
|
||||
break;
|
||||
case VideoParams::kFormatFloat32:
|
||||
case PixelFormat::F32:
|
||||
return OCIO::BIT_DEPTH_F32;
|
||||
break;
|
||||
case VideoParams::kFormatInvalid:
|
||||
case VideoParams::kFormatCount:
|
||||
case PixelFormat::INVALID:
|
||||
case PixelFormat::COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace olive {
|
||||
class OCIOUtils
|
||||
{
|
||||
public:
|
||||
static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(VideoParams::Format format);
|
||||
static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(PixelFormat format);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "oiioutils.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace olive {
|
||||
|
||||
void OIIOUtils::FrameToBuffer(const Frame* frame, OIIO::ImageBuf *buf)
|
||||
@@ -45,7 +47,7 @@ rational OIIOUtils::GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec)
|
||||
return rational::fromDouble(spec.get_float_attribute("PixelAspectRatio", 1));
|
||||
}
|
||||
|
||||
VideoParams::Format OIIOUtils::GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type)
|
||||
PixelFormat OIIOUtils::GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type)
|
||||
{
|
||||
switch (type) {
|
||||
case OIIO::TypeDesc::UNKNOWN:
|
||||
@@ -66,16 +68,16 @@ VideoParams::Format OIIOUtils::GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYP
|
||||
break;
|
||||
|
||||
case OIIO::TypeDesc::UINT8:
|
||||
return VideoParams::kFormatUnsigned8;
|
||||
return PixelFormat::U8;
|
||||
case OIIO::TypeDesc::UINT16:
|
||||
return VideoParams::kFormatUnsigned16;
|
||||
return PixelFormat::U16;
|
||||
case OIIO::TypeDesc::HALF:
|
||||
return VideoParams::kFormatFloat16;
|
||||
return PixelFormat::F16;
|
||||
case OIIO::TypeDesc::FLOAT:
|
||||
return VideoParams::kFormatFloat32;
|
||||
return PixelFormat::F32;
|
||||
}
|
||||
|
||||
return VideoParams::kFormatInvalid;
|
||||
return PixelFormat::INVALID;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,19 +31,19 @@ namespace olive {
|
||||
|
||||
class OIIOUtils {
|
||||
public:
|
||||
static OIIO::TypeDesc::BASETYPE GetOIIOBaseTypeFromFormat(VideoParams::Format format)
|
||||
static OIIO::TypeDesc::BASETYPE GetOIIOBaseTypeFromFormat(PixelFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case VideoParams::kFormatUnsigned8:
|
||||
case PixelFormat::U8:
|
||||
return OIIO::TypeDesc::UINT8;
|
||||
case VideoParams::kFormatUnsigned16:
|
||||
case PixelFormat::U16:
|
||||
return OIIO::TypeDesc::UINT16;
|
||||
case VideoParams::kFormatFloat16:
|
||||
case PixelFormat::F16:
|
||||
return OIIO::TypeDesc::HALF;
|
||||
case VideoParams::kFormatFloat32:
|
||||
case PixelFormat::F32:
|
||||
return OIIO::TypeDesc::FLOAT;
|
||||
case VideoParams::kFormatInvalid:
|
||||
case VideoParams::kFormatCount:
|
||||
case PixelFormat::INVALID:
|
||||
case PixelFormat::COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
|
||||
static void BufferToFrame(OIIO::ImageBuf* buf, Frame* frame);
|
||||
|
||||
static VideoParams::Format GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type);
|
||||
static PixelFormat GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type);
|
||||
|
||||
static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec& spec);
|
||||
|
||||
|
||||
@@ -172,4 +172,32 @@ void QtUtils::SetComboBoxData(QComboBox *cb, int data)
|
||||
}
|
||||
}
|
||||
|
||||
QColor QtUtils::toQColor(const core::Color &i)
|
||||
{
|
||||
QColor c;
|
||||
|
||||
// QColor only supports values from 0.0 to 1.0 and are only used for UI representations
|
||||
c.setRedF(std::clamp(i.red(), 0.0f, 1.0f));
|
||||
c.setGreenF(std::clamp(i.green(), 0.0f, 1.0f));
|
||||
c.setBlueF(std::clamp(i.blue(), 0.0f, 1.0f));
|
||||
c.setAlphaF(std::clamp(i.alpha(), 0.0f, 1.0f));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
namespace core {
|
||||
|
||||
uint qHash(const core::rational &r, uint seed)
|
||||
{
|
||||
return ::qHash(r.toDouble(), seed);
|
||||
}
|
||||
|
||||
uint qHash(const core::TimeRange &r, uint seed)
|
||||
{
|
||||
return qHash(r.in(), seed) ^ qHash(r.out(), seed);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef QTVERSIONABSTRACTION_H
|
||||
#define QTVERSIONABSTRACTION_H
|
||||
|
||||
#include <olive/core/core.h>
|
||||
#include <QComboBox>
|
||||
#include <QDateTime>
|
||||
#include <QFileInfo>
|
||||
@@ -72,8 +73,24 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static QColor toQColor(const core::Color &c);
|
||||
|
||||
};
|
||||
|
||||
namespace core {
|
||||
|
||||
uint qHash(const core::rational& r, uint seed = 0);
|
||||
uint qHash(const core::TimeRange& r, uint seed = 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(olive::core::rational);
|
||||
Q_DECLARE_METATYPE(olive::core::Color);
|
||||
Q_DECLARE_METATYPE(olive::core::TimeRange);
|
||||
Q_DECLARE_METATYPE(olive::core::Bezier);
|
||||
Q_DECLARE_METATYPE(olive::core::AudioParams);
|
||||
Q_DECLARE_METATYPE(olive::core::SampleBuffer);
|
||||
|
||||
#endif // QTVERSIONABSTRACTION_H
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
#include <QInputDialog>
|
||||
|
||||
#include "common/rational.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
double GetFloatRatioFromUser(QWidget* parent,
|
||||
|
||||
@@ -1,287 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "rational.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
const rational rational::NaN = rational(0, 0);
|
||||
|
||||
rational rational::fromDouble(const double &flt, bool* ok)
|
||||
{
|
||||
if (qIsNaN(flt)) {
|
||||
// Return NaN rational
|
||||
if (ok) *ok = false;
|
||||
return NaN;
|
||||
}
|
||||
|
||||
// Use FFmpeg function for the time being
|
||||
AVRational r = av_d2q(flt, INT_MAX);
|
||||
|
||||
if (r.den == 0) {
|
||||
// If den == 0, we were unable to convert to a rational
|
||||
if (ok) {
|
||||
*ok = false;
|
||||
}
|
||||
} else {
|
||||
// Otherwise, assume we received a real rational
|
||||
if (ok) {
|
||||
*ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
rational rational::fromString(const QString &str, bool* ok)
|
||||
{
|
||||
QStringList elements = str.split('/');
|
||||
|
||||
switch (elements.size()) {
|
||||
case 1:
|
||||
return rational(elements.first().toInt(ok));
|
||||
case 2:
|
||||
return rational(elements.at(0).toInt(ok), elements.at(1).toInt(ok));
|
||||
default:
|
||||
// Returns NaN with ok set to false
|
||||
if (ok) {
|
||||
*ok = false;
|
||||
}
|
||||
return NaN;
|
||||
}
|
||||
}
|
||||
|
||||
//Function: convert to double
|
||||
|
||||
double rational::toDouble() const
|
||||
{
|
||||
if (r_.den != 0) {
|
||||
return av_q2d(r_);
|
||||
} else {
|
||||
return qSNaN();
|
||||
}
|
||||
}
|
||||
|
||||
AVRational rational::toAVRational() const
|
||||
{
|
||||
return r_;
|
||||
}
|
||||
|
||||
#ifdef USE_OTIO
|
||||
opentime::RationalTime rational::toRationalTime(double framerate) const
|
||||
{
|
||||
// Is this the best way of doing this?
|
||||
// Olive can store rationals as 0/0 which causes errors in OTIO
|
||||
opentime::RationalTime time = opentime::RationalTime(r_.num, r_.den == 0 ? 1 : r_.den);
|
||||
return time.rescaled_to(framerate);
|
||||
}
|
||||
#endif
|
||||
|
||||
rational rational::flipped() const
|
||||
{
|
||||
rational r = *this;
|
||||
r.flip();
|
||||
return r;
|
||||
}
|
||||
|
||||
void rational::flip()
|
||||
{
|
||||
if (!isNull()) {
|
||||
std::swap(r_.den, r_.num);
|
||||
FixSigns();
|
||||
}
|
||||
}
|
||||
|
||||
QString rational::toString() const
|
||||
{
|
||||
return QStringLiteral("%1/%2").arg(QString::number(r_.num), QString::number(r_.den));
|
||||
}
|
||||
|
||||
void rational::FixSigns()
|
||||
{
|
||||
if (r_.den < 0) {
|
||||
// Normalize so that denominator is always positive
|
||||
r_.den = -r_.den;
|
||||
r_.num = -r_.num;
|
||||
} else if (r_.den == 0) {
|
||||
// Normalize to 0/0 (aka NaN) if denominator is zero
|
||||
r_.num = 0;
|
||||
} else if (r_.num == 0) {
|
||||
// Normalize to 0/1 if numerator is zero
|
||||
r_.den = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void rational::Reduce()
|
||||
{
|
||||
av_reduce(&r_.num, &r_.den, r_.num, r_.den, INT_MAX);
|
||||
}
|
||||
|
||||
//Assignment Operators
|
||||
|
||||
const rational& rational::operator=(const rational &rhs)
|
||||
{
|
||||
r_ = rhs.r_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const rational& rational::operator+=(const rational &rhs)
|
||||
{
|
||||
Q_ASSERT(*this != RATIONAL_MIN && *this != RATIONAL_MAX && rhs != RATIONAL_MIN && rhs != RATIONAL_MAX);
|
||||
|
||||
if (!isNaN()) {
|
||||
if (rhs.isNaN()) {
|
||||
*this = NaN;
|
||||
} else {
|
||||
r_ = av_add_q(r_, rhs.r_);
|
||||
FixSigns();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const rational& rational::operator-=(const rational &rhs)
|
||||
{
|
||||
Q_ASSERT(*this != RATIONAL_MIN && *this != RATIONAL_MAX && rhs != RATIONAL_MIN && rhs != RATIONAL_MAX);
|
||||
|
||||
if (!isNaN()) {
|
||||
if (rhs.isNaN()) {
|
||||
*this = NaN;
|
||||
} else {
|
||||
r_ = av_sub_q(r_, rhs.r_);
|
||||
FixSigns();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const rational& rational::operator*=(const rational &rhs)
|
||||
{
|
||||
Q_ASSERT(*this != RATIONAL_MIN && *this != RATIONAL_MAX && rhs != RATIONAL_MIN && rhs != RATIONAL_MAX);
|
||||
|
||||
if (!isNaN()) {
|
||||
if (rhs.isNaN()) {
|
||||
*this = NaN;
|
||||
} else {
|
||||
r_ = av_mul_q(r_, rhs.r_);
|
||||
FixSigns();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const rational& rational::operator/=(const rational &rhs)
|
||||
{
|
||||
Q_ASSERT(*this != RATIONAL_MIN && *this != RATIONAL_MAX && rhs != RATIONAL_MIN && rhs != RATIONAL_MAX);
|
||||
|
||||
if (!isNaN()) {
|
||||
if (rhs.isNaN()) {
|
||||
*this = NaN;
|
||||
} else {
|
||||
r_ = av_div_q(r_, rhs.r_);
|
||||
FixSigns();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Binary math operators
|
||||
|
||||
rational rational::operator+(const rational &rhs) const
|
||||
{
|
||||
rational answer(*this);
|
||||
answer += rhs;
|
||||
return answer;
|
||||
}
|
||||
|
||||
rational rational::operator-(const rational &rhs) const
|
||||
{
|
||||
rational answer(*this);
|
||||
answer -= rhs;
|
||||
return answer;
|
||||
}
|
||||
|
||||
rational rational::operator/(const rational &rhs) const
|
||||
{
|
||||
rational answer(*this);
|
||||
answer /= rhs;
|
||||
return answer;
|
||||
}
|
||||
|
||||
rational rational::operator*(const rational &rhs) const
|
||||
{
|
||||
rational answer(*this);
|
||||
answer *= rhs;
|
||||
return answer;
|
||||
}
|
||||
|
||||
//Relational and equality operators
|
||||
|
||||
bool rational::operator<(const rational &rhs) const
|
||||
{
|
||||
return av_cmp_q(r_, rhs.r_) == -1;
|
||||
}
|
||||
|
||||
bool rational::operator<=(const rational &rhs) const
|
||||
{
|
||||
int cmp = av_cmp_q(r_, rhs.r_);
|
||||
return cmp == 0 || cmp == -1;
|
||||
}
|
||||
|
||||
bool rational::operator>(const rational &rhs) const
|
||||
{
|
||||
return av_cmp_q(r_, rhs.r_) == 1;
|
||||
}
|
||||
|
||||
bool rational::operator>=(const rational &rhs) const
|
||||
{
|
||||
int cmp = av_cmp_q(r_, rhs.r_);
|
||||
return cmp == 0 || cmp == 1;
|
||||
}
|
||||
|
||||
bool rational::operator==(const rational &rhs) const
|
||||
{
|
||||
return av_cmp_q(r_, rhs.r_) == 0;
|
||||
}
|
||||
|
||||
bool rational::operator!=(const rational &rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
uint qHash(const rational &r, uint seed)
|
||||
{
|
||||
return ::qHash(r.toDouble(), seed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const olive::rational &r)
|
||||
{
|
||||
if (r.isNaN()) {
|
||||
return debug.space() << "NaN";
|
||||
} else {
|
||||
return debug.space() << r.toDouble();
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef RATIONAL_H
|
||||
#define RATIONAL_H
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/rational.h>
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
#include <QDebug>
|
||||
#include <QMetaType>
|
||||
|
||||
#ifdef USE_OTIO
|
||||
#include <opentime/rationalTime.h>
|
||||
#endif
|
||||
|
||||
#include "common/define.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class rational
|
||||
{
|
||||
public:
|
||||
rational(const int &numerator = 0)
|
||||
{
|
||||
r_.num = numerator;
|
||||
r_.den = 1;
|
||||
}
|
||||
|
||||
rational(const int &numerator, const int &denominator)
|
||||
{
|
||||
r_.num = numerator;
|
||||
r_.den = denominator;
|
||||
|
||||
FixSigns();
|
||||
Reduce();
|
||||
}
|
||||
|
||||
rational(const rational &rhs) = default;
|
||||
|
||||
rational(const AVRational& r)
|
||||
{
|
||||
r_ = r;
|
||||
|
||||
FixSigns();
|
||||
}
|
||||
|
||||
static rational fromDouble(const double& flt, bool *ok = nullptr);
|
||||
static rational fromString(const QString& str, bool* ok = nullptr);
|
||||
|
||||
static const rational NaN;
|
||||
|
||||
//Assignment Operators
|
||||
const rational& operator=(const rational &rhs);
|
||||
const rational& operator+=(const rational &rhs);
|
||||
const rational& operator-=(const rational &rhs);
|
||||
const rational& operator/=(const rational &rhs);
|
||||
const rational& operator*=(const rational &rhs);
|
||||
|
||||
//Binary math operators
|
||||
rational operator+(const rational &rhs) const;
|
||||
rational operator-(const rational &rhs) const;
|
||||
rational operator/(const rational &rhs) const;
|
||||
rational operator*(const rational &rhs) const;
|
||||
|
||||
//Relational and equality operators
|
||||
bool operator<(const rational &rhs) const;
|
||||
bool operator<=(const rational &rhs) const;
|
||||
bool operator>(const rational &rhs) const;
|
||||
bool operator>=(const rational &rhs) const;
|
||||
bool operator==(const rational &rhs) const;
|
||||
bool operator!=(const rational &rhs) const;
|
||||
|
||||
//Unary operators
|
||||
const rational& operator+() const { return *this; }
|
||||
rational operator-() const { return rational(r_.num, -r_.den); }
|
||||
bool operator!() const { return !r_.num; }
|
||||
|
||||
//Function: convert to double
|
||||
double toDouble() const;
|
||||
|
||||
AVRational toAVRational() const;
|
||||
|
||||
#ifdef USE_OTIO
|
||||
static rational fromRationalTime(const opentime::RationalTime &t)
|
||||
{
|
||||
// Is this the best way to do this?
|
||||
return fromDouble(t.to_seconds());
|
||||
}
|
||||
|
||||
// Convert Olive rationals to opentime rationals with the given framerate (defaults to 24)
|
||||
opentime::RationalTime toRationalTime(double framerate = 24) const;
|
||||
#endif
|
||||
|
||||
// Produce "flipped" version
|
||||
rational flipped() const;
|
||||
void flip();
|
||||
|
||||
// Returns whether the rational is valid but equal to zero or not
|
||||
//
|
||||
// A NaN is always a null, but a null is not always a NaN
|
||||
bool isNull() const { return r_.num == 0; }
|
||||
|
||||
// Returns whether this rational is not a valid number (denominator == 0)
|
||||
bool isNaN() const { return r_.den == 0; }
|
||||
|
||||
const int& numerator() const { return r_.num; }
|
||||
const int& denominator() const { return r_.den; }
|
||||
|
||||
QString toString() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream &out, const rational &value)
|
||||
{
|
||||
out << value.r_.num << '/' << value.r_.den;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
void FixSigns();
|
||||
void Reduce();
|
||||
|
||||
AVRational r_;
|
||||
|
||||
};
|
||||
|
||||
#define RATIONAL_MIN rational(INT_MIN)
|
||||
#define RATIONAL_MAX rational(INT_MAX)
|
||||
|
||||
uint qHash(const rational& r, uint seed = 0);
|
||||
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const olive::rational& r);
|
||||
|
||||
Q_DECLARE_METATYPE(olive::rational)
|
||||
|
||||
#endif // RATIONAL_H
|
||||
@@ -1,358 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "timecodefunctions.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/mathematics.h>
|
||||
}
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QtMath>
|
||||
|
||||
#include "config/config.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
QString padded(int64_t arg, int padding) {
|
||||
return QStringLiteral("%1").arg(arg, padding, 10, QChar('0'));
|
||||
}
|
||||
|
||||
QString Timecode::time_to_timecode(const rational &time, const rational &timebase, const Timecode::Display &display, bool show_plus_if_positive)
|
||||
{
|
||||
if (timebase.isNull()) {
|
||||
return QStringLiteral("INVALID TIMEBASE");
|
||||
}
|
||||
|
||||
double time_dbl = time.toDouble();
|
||||
|
||||
switch (display) {
|
||||
case kTimecodeNonDropFrame:
|
||||
case kTimecodeDropFrame:
|
||||
case kTimecodeSeconds:
|
||||
{
|
||||
QString prefix;
|
||||
|
||||
if (time_dbl < 0) {
|
||||
prefix = "-";
|
||||
} else if (show_plus_if_positive) {
|
||||
prefix = "+";
|
||||
}
|
||||
|
||||
if (display == kTimecodeSeconds) {
|
||||
time_dbl = qAbs(time_dbl);
|
||||
|
||||
int64_t total_seconds = qFloor(time_dbl);
|
||||
|
||||
int64_t hours = total_seconds / 3600;
|
||||
int64_t mins = total_seconds / 60 - hours * 60;
|
||||
int64_t secs = total_seconds - mins * 60;
|
||||
int64_t fraction = qRound64((time_dbl - static_cast<double>(total_seconds)) * 1000);
|
||||
|
||||
return QStringLiteral("%1%2:%3:%4.%5").arg(prefix,
|
||||
padded(hours, 2),
|
||||
padded(mins, 2),
|
||||
padded(secs, 2),
|
||||
padded(fraction, 3));
|
||||
} else {
|
||||
// Determine what symbol to separate frames (";" is used for drop frame, ":" is non-drop frame)
|
||||
QString frame_token;
|
||||
double frame_rate = timebase.flipped().toDouble();
|
||||
int rounded_frame_rate = qRound(frame_rate);
|
||||
int64_t frames, secs, mins, hours;
|
||||
int64_t f = qAbs(time_to_timestamp(time, timebase));
|
||||
|
||||
if (display == kTimecodeDropFrame && TimebaseIsDropFrame(timebase)) {
|
||||
frame_token = ";";
|
||||
|
||||
/**
|
||||
* CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE
|
||||
*
|
||||
* Code by David Heidelberger, adapted from Andrew Duncan, further adapted for Olive by Olive Team
|
||||
* Given an int called framenumber and a double called framerate
|
||||
* Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off.
|
||||
*/
|
||||
|
||||
// If frame number is greater than 24 hrs, next operation will rollover clock
|
||||
f %= (qRound(frame_rate*3600)*24);
|
||||
|
||||
// Number of frames per ten minutes
|
||||
int64_t framesPer10Minutes = qRound(frame_rate * 600);
|
||||
int64_t d = f / framesPer10Minutes;
|
||||
int64_t m = f % framesPer10Minutes;
|
||||
|
||||
// Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
|
||||
int64_t dropFrames = qRound(frame_rate * (2.0/30.0));
|
||||
|
||||
// Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
|
||||
f += dropFrames*9*d;
|
||||
if (m > dropFrames) {
|
||||
f += dropFrames * ((m - dropFrames) / (qRound(frame_rate)*60 - dropFrames));
|
||||
}
|
||||
} else {
|
||||
frame_token = ":";
|
||||
}
|
||||
|
||||
// non-drop timecode
|
||||
hours = f / (3600*rounded_frame_rate);
|
||||
mins = f / (60*rounded_frame_rate) % 60;
|
||||
secs = f / rounded_frame_rate % 60;
|
||||
frames = f % rounded_frame_rate;
|
||||
|
||||
return QStringLiteral("%1%2:%3:%4%5%6").arg(prefix,
|
||||
padded(hours, 2),
|
||||
padded(mins, 2),
|
||||
padded(secs, 2),
|
||||
frame_token,
|
||||
padded(frames, 2));
|
||||
}
|
||||
}
|
||||
case kFrames:
|
||||
return QString::number(time_to_timestamp(time, timebase));
|
||||
case kMilliseconds:
|
||||
return QString::number(qRound(time_dbl * 1000));
|
||||
}
|
||||
|
||||
return QStringLiteral("INVALID TIMECODE MODE");
|
||||
}
|
||||
|
||||
int64_t StrToInt64EmptyTolerant(const QString &s, bool *ok)
|
||||
{
|
||||
if (s.isEmpty()) {
|
||||
if (ok) *ok = true;
|
||||
return 0;
|
||||
} else {
|
||||
return s.toLongLong(ok);
|
||||
}
|
||||
}
|
||||
|
||||
double StrToDoubleEmptyTolerant(const QString &s, bool *ok)
|
||||
{
|
||||
if (s.isEmpty()) {
|
||||
if (ok) *ok = true;
|
||||
return 0;
|
||||
} else {
|
||||
return s.toDouble(ok);
|
||||
}
|
||||
}
|
||||
|
||||
rational Timecode::timecode_to_time(const QString &timecode, const rational &timebase, const Timecode::Display &display, bool *ok)
|
||||
{
|
||||
if (timecode.isEmpty()) {
|
||||
goto err_fatal;
|
||||
}
|
||||
|
||||
switch (display) {
|
||||
case kTimecodeNonDropFrame:
|
||||
case kTimecodeDropFrame:
|
||||
case kTimecodeSeconds:
|
||||
{
|
||||
QStringList timecode_split = timecode.split(QRegularExpression("(:)|(;)"));
|
||||
|
||||
const int element_count = display == kTimecodeSeconds ? 3 : 4;
|
||||
|
||||
// Remove excess tokens (we're only interested in HH:MM:SS.FF)
|
||||
while (timecode_split.size() > element_count) {
|
||||
timecode_split.removeLast();
|
||||
}
|
||||
|
||||
// For easier index calculations, ensure minimum size
|
||||
while (timecode_split.size() < element_count) {
|
||||
timecode_split.prepend(QString());
|
||||
}
|
||||
|
||||
bool negative = timecode.trimmed().startsWith('-');
|
||||
|
||||
double frame_rate = timebase.flipped().toDouble();
|
||||
int rounded_frame_rate = qRound(frame_rate);
|
||||
|
||||
bool valid;
|
||||
rational time;
|
||||
|
||||
int64_t hours = StrToInt64EmptyTolerant(timecode_split.at(0), &valid);
|
||||
if (!valid) goto err_fatal;
|
||||
int64_t mins = StrToInt64EmptyTolerant(timecode_split.at(1), &valid);
|
||||
if (!valid) goto err_fatal;
|
||||
|
||||
if (display == kTimecodeSeconds) {
|
||||
double secs = StrToDoubleEmptyTolerant(timecode_split.at(2), &valid);
|
||||
if (!valid) goto err_fatal;
|
||||
|
||||
time = rational::fromDouble(hours * 3600 + mins * 60 + secs);
|
||||
} else {
|
||||
int64_t secs = StrToInt64EmptyTolerant(timecode_split.at(2), &valid);
|
||||
if (!valid) goto err_fatal;
|
||||
int64_t frames = StrToInt64EmptyTolerant(timecode_split.at(3), &valid);
|
||||
if (!valid) goto err_fatal;
|
||||
|
||||
int64_t sec_count = (hours*3600 + mins*60 + secs);
|
||||
int64_t frame_count = sec_count*rounded_frame_rate + frames;
|
||||
|
||||
if (display == kTimecodeDropFrame && TimebaseIsDropFrame(timebase)) {
|
||||
|
||||
// Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
|
||||
int64_t dropFrames = qRound64(frame_rate * (2.0/30.0));
|
||||
|
||||
// d and m need to be calculated from
|
||||
int64_t real_fr_ts = qRound64(static_cast<double>(sec_count)*frame_rate) + frames;
|
||||
|
||||
int64_t framesPer10Minutes = qRound(frame_rate * 600);
|
||||
int64_t d = real_fr_ts / framesPer10Minutes;
|
||||
int64_t m = real_fr_ts % framesPer10Minutes;
|
||||
|
||||
if (m > dropFrames) {
|
||||
frame_count -= dropFrames * ((m - dropFrames) / (qRound(frame_rate)*60 - dropFrames));
|
||||
}
|
||||
frame_count -= dropFrames*9*d;
|
||||
}
|
||||
|
||||
time = timestamp_to_time(frame_count, timebase);
|
||||
}
|
||||
|
||||
if (ok) *ok = true;
|
||||
|
||||
if (negative) time = -time;
|
||||
|
||||
return time;
|
||||
}
|
||||
case kMilliseconds:
|
||||
{
|
||||
bool valid;
|
||||
double timecode_secs = timecode.toDouble(&valid);
|
||||
|
||||
if (valid) {
|
||||
// Convert milliseconds to seconds
|
||||
timecode_secs *= 0.001;
|
||||
|
||||
// Convert seconds to rational
|
||||
return rational::fromDouble(timecode_secs, ok);
|
||||
} else {
|
||||
goto err_fatal;
|
||||
}
|
||||
}
|
||||
case kFrames:
|
||||
{
|
||||
bool valid;
|
||||
int64_t ts = timecode.toLongLong(&valid);
|
||||
if (!valid) {
|
||||
goto err_fatal;
|
||||
}
|
||||
|
||||
if (ok) *ok = true;
|
||||
return timestamp_to_time(ts, timebase);
|
||||
}
|
||||
}
|
||||
|
||||
err_fatal:
|
||||
if (ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rational Timecode::snap_time_to_timebase(const rational &time, const rational &timebase, Rounding floor)
|
||||
{
|
||||
// Just convert to a timestamp in timebase units and back
|
||||
int64_t timestamp = time_to_timestamp(time, timebase, floor);
|
||||
|
||||
return timestamp_to_time(timestamp, timebase);
|
||||
}
|
||||
|
||||
rational Timecode::timestamp_to_time(const int64_t ×tamp, const rational &timebase)
|
||||
{
|
||||
int64_t num = int64_t(timebase.numerator()) * timestamp;
|
||||
int64_t den = timebase.denominator();
|
||||
|
||||
int num_r, den_r;
|
||||
|
||||
av_reduce(&num_r, &den_r, num, den, INT_MAX);
|
||||
|
||||
return rational(num_r, den_r);
|
||||
}
|
||||
|
||||
bool Timecode::TimebaseIsDropFrame(const rational &timebase)
|
||||
{
|
||||
return (timebase.numerator() != 1);
|
||||
}
|
||||
|
||||
QString Timecode::TimeToString(int64_t ms)
|
||||
{
|
||||
int64_t total_seconds = ms / 1000;
|
||||
int64_t ss = total_seconds % 60;
|
||||
int64_t mm = (total_seconds / 60) % 60;
|
||||
int64_t hh = total_seconds / 3600;
|
||||
|
||||
return QStringLiteral("%1:%2:%3")
|
||||
.arg(hh, 2, 10, QChar('0'))
|
||||
.arg(mm, 2, 10, QChar('0'))
|
||||
.arg(ss, 2, 10, QChar('0'));
|
||||
}
|
||||
|
||||
int64_t Timecode::time_to_timestamp(const rational &time, const rational &timebase, Rounding floor)
|
||||
{
|
||||
return time_to_timestamp(time.toDouble(), timebase, floor);
|
||||
}
|
||||
|
||||
int64_t Timecode::time_to_timestamp(const double &time, const rational &timebase, Rounding floor)
|
||||
{
|
||||
const double d = time * timebase.flipped().toDouble();
|
||||
|
||||
if (std::isnan(d)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const double eps = 0.000000000001;
|
||||
|
||||
switch (floor) {
|
||||
case kRound:
|
||||
default:
|
||||
return qRound64(d);
|
||||
case kFloor:
|
||||
if (d > qCeil(d)-eps) {
|
||||
return qCeil(d);
|
||||
} else {
|
||||
return qFloor(d);
|
||||
}
|
||||
case kCeil:
|
||||
if (d < qFloor(d)+eps) {
|
||||
return qFloor(d);
|
||||
} else {
|
||||
return qCeil(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Timecode::rescale_timestamp(const int64_t &ts, const rational &source, const rational &dest)
|
||||
{
|
||||
if (source == dest) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
return av_rescale_q(ts, source.toAVRational(), dest.toAVRational());
|
||||
}
|
||||
|
||||
int64_t Timecode::rescale_timestamp_ceil(const int64_t &ts, const rational &source, const rational &dest)
|
||||
{
|
||||
if (source == dest) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
return av_rescale_q_rnd(ts, source.toAVRational(), dest.toAVRational(), AV_ROUND_UP);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef TIMECODEFUNCTIONS_H
|
||||
#define TIMECODEFUNCTIONS_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "common/rational.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
/**
|
||||
* @brief Functions for converting times/timecodes/timestamps
|
||||
*
|
||||
* Olive uses the following terminology through its code:
|
||||
*
|
||||
* `time` - time in seconds presented in a rational form
|
||||
* `timebase` - the base time unit of an audio/video stream in seconds
|
||||
* `timestamp` - an integer representation of a time in timebase units (in many cases is used like a frame number)
|
||||
* `timecode` a user-friendly string representation of a time according to Timecode::Display
|
||||
*/
|
||||
class Timecode {
|
||||
public:
|
||||
enum Display {
|
||||
kTimecodeDropFrame,
|
||||
kTimecodeNonDropFrame,
|
||||
kTimecodeSeconds,
|
||||
kFrames,
|
||||
kMilliseconds
|
||||
};
|
||||
|
||||
enum Rounding {
|
||||
kCeil,
|
||||
kFloor,
|
||||
kRound
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Convert a timestamp (according to a rational timebase) to a user-friendly string representation
|
||||
*/
|
||||
static QString time_to_timecode(const rational& time, const rational& timebase, const Display &display, bool show_plus_if_positive = false);
|
||||
static rational timecode_to_time(const QString& timecode, const rational& timebase, const Display& display, bool *ok = nullptr);
|
||||
|
||||
static rational snap_time_to_timebase(const rational& time, const rational& timebase, Rounding floor = kRound);
|
||||
|
||||
static int64_t time_to_timestamp(const rational& time, const rational& timebase, Rounding floor = kRound);
|
||||
static int64_t time_to_timestamp(const double& time, const rational& timebase, Rounding floor = kRound);
|
||||
|
||||
static int64_t rescale_timestamp(const int64_t& ts, const rational& source, const rational& dest);
|
||||
static int64_t rescale_timestamp_ceil(const int64_t& ts, const rational& source, const rational& dest);
|
||||
|
||||
static rational timestamp_to_time(const int64_t& timestamp, const rational& timebase);
|
||||
|
||||
static bool TimebaseIsDropFrame(const rational& timebase);
|
||||
|
||||
static QString TimeToString(int64_t ms);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TIMECODEFUNCTIONS_H
|
||||
@@ -1,393 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "timerange.h"
|
||||
|
||||
#include <QtMath>
|
||||
#include <utility>
|
||||
|
||||
namespace olive {
|
||||
|
||||
TimeRange::TimeRange(const rational &in, const rational &out) :
|
||||
in_(in),
|
||||
out_(out)
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
|
||||
const rational &TimeRange::in() const
|
||||
{
|
||||
return in_;
|
||||
}
|
||||
|
||||
const rational &TimeRange::out() const
|
||||
{
|
||||
return out_;
|
||||
}
|
||||
|
||||
const rational &TimeRange::length() const
|
||||
{
|
||||
Q_ASSERT(!length_.isNaN());
|
||||
return length_;
|
||||
}
|
||||
|
||||
void TimeRange::set_in(const rational &in)
|
||||
{
|
||||
in_ = in;
|
||||
normalize();
|
||||
}
|
||||
|
||||
void TimeRange::set_out(const rational &out)
|
||||
{
|
||||
out_ = out;
|
||||
normalize();
|
||||
}
|
||||
|
||||
void TimeRange::set_range(const rational &in, const rational &out)
|
||||
{
|
||||
in_ = in;
|
||||
out_ = out;
|
||||
normalize();
|
||||
}
|
||||
|
||||
bool TimeRange::operator==(const TimeRange &r) const
|
||||
{
|
||||
return in() == r.in() && out() == r.out();
|
||||
}
|
||||
|
||||
bool TimeRange::operator!=(const TimeRange &r) const
|
||||
{
|
||||
return in() != r.in() || out() != r.out();
|
||||
}
|
||||
|
||||
bool TimeRange::OverlapsWith(const TimeRange &a, bool in_inclusive, bool out_inclusive) const
|
||||
{
|
||||
bool doesnt_overlap_in = (in_inclusive) ? (a.out() < in()) : (a.out() <= in());
|
||||
|
||||
bool doesnt_overlap_out = (out_inclusive) ? (a.in() > out()) : (a.in() >= out());
|
||||
|
||||
return !doesnt_overlap_in && !doesnt_overlap_out;
|
||||
}
|
||||
|
||||
TimeRange TimeRange::Combined(const TimeRange &a) const
|
||||
{
|
||||
return Combine(a, *this);
|
||||
}
|
||||
|
||||
bool TimeRange::Contains(const TimeRange &compare, bool in_inclusive, bool out_inclusive) const
|
||||
{
|
||||
bool contains_in = (in_inclusive) ? (compare.in() >= in()) : (compare.in() > in());
|
||||
|
||||
bool contains_out = (out_inclusive) ? (compare.out() <= out()) : (compare.out() < out());
|
||||
|
||||
return contains_in && contains_out;
|
||||
}
|
||||
|
||||
bool TimeRange::Contains(const rational &r) const
|
||||
{
|
||||
return r >= in_ && r < out_;
|
||||
}
|
||||
|
||||
TimeRange TimeRange::Combine(const TimeRange &a, const TimeRange &b)
|
||||
{
|
||||
return TimeRange(qMin(a.in(), b.in()),
|
||||
qMax(a.out(), b.out()));
|
||||
}
|
||||
|
||||
TimeRange TimeRange::Intersected(const TimeRange &a) const
|
||||
{
|
||||
return Intersect(a, *this);
|
||||
}
|
||||
|
||||
TimeRange TimeRange::Intersect(const TimeRange &a, const TimeRange &b)
|
||||
{
|
||||
return TimeRange(qMax(a.in(), b.in()),
|
||||
qMin(a.out(), b.out()));
|
||||
}
|
||||
|
||||
TimeRange TimeRange::operator+(const rational &rhs) const
|
||||
{
|
||||
TimeRange answer(*this);
|
||||
answer += rhs;
|
||||
return answer;
|
||||
}
|
||||
|
||||
TimeRange TimeRange::operator-(const rational &rhs) const
|
||||
{
|
||||
TimeRange answer(*this);
|
||||
answer -= rhs;
|
||||
return answer;
|
||||
}
|
||||
|
||||
const TimeRange &TimeRange::operator+=(const rational &rhs)
|
||||
{
|
||||
set_range(in_ + rhs, out_ + rhs);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const TimeRange &TimeRange::operator-=(const rational &rhs)
|
||||
{
|
||||
set_range(in_ - rhs, out_ - rhs);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::list<TimeRange> TimeRange::Split(const int &chunk_size) const
|
||||
{
|
||||
std::list<TimeRange> split_ranges;
|
||||
|
||||
int start_time = qFloor(this->in().toDouble() / static_cast<double>(chunk_size)) * chunk_size;
|
||||
int end_time = qCeil(this->out().toDouble() / static_cast<double>(chunk_size)) * chunk_size;
|
||||
|
||||
for (int i=start_time; i<end_time; i+=chunk_size) {
|
||||
split_ranges.push_back(TimeRange(qMax(this->in(), rational(i)),
|
||||
qMin(this->out(), rational(i + chunk_size))));
|
||||
}
|
||||
|
||||
return split_ranges;
|
||||
}
|
||||
|
||||
void TimeRange::normalize()
|
||||
{
|
||||
// If `out` is earlier than `in`, swap them
|
||||
if (out_ < in_)
|
||||
{
|
||||
std::swap(out_, in_);
|
||||
}
|
||||
|
||||
// Calculate length
|
||||
if (out_ == RATIONAL_MIN || out_ == RATIONAL_MAX || in_ == RATIONAL_MIN || in_ == RATIONAL_MAX) {
|
||||
length_ = rational::NaN;
|
||||
} else {
|
||||
length_ = out_ - in_;
|
||||
}
|
||||
}
|
||||
|
||||
void TimeRangeList::insert(const TimeRangeList &list_to_add)
|
||||
{
|
||||
for (auto it=list_to_add.cbegin(); it!=list_to_add.cend(); it++) {
|
||||
insert(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void TimeRangeList::insert(TimeRange range_to_add)
|
||||
{
|
||||
// See if list contains this range
|
||||
if (contains(range_to_add)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Does not contain range, so we'll almost certainly be adding it in some way
|
||||
for (int i=0;i<size();i++) {
|
||||
const TimeRange& compare = array_.at(i);
|
||||
|
||||
if (compare.OverlapsWith(range_to_add)) {
|
||||
range_to_add = TimeRange::Combine(range_to_add, compare);
|
||||
array_.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
array_.append(range_to_add);
|
||||
}
|
||||
|
||||
void TimeRangeList::remove(const TimeRange &remove)
|
||||
{
|
||||
util_remove(&array_, remove);
|
||||
}
|
||||
|
||||
void TimeRangeList::remove(const TimeRangeList &list)
|
||||
{
|
||||
for (const TimeRange &r : list) {
|
||||
remove(r);
|
||||
}
|
||||
}
|
||||
|
||||
bool TimeRangeList::contains(const TimeRange &range, bool in_inclusive, bool out_inclusive) const
|
||||
{
|
||||
for (int i=0;i<size();i++) {
|
||||
if (array_.at(i).Contains(range, in_inclusive, out_inclusive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TimeRangeList::shift(const rational &diff)
|
||||
{
|
||||
for (int i=0; i<array_.size(); i++) {
|
||||
array_[i] += diff;
|
||||
}
|
||||
}
|
||||
|
||||
void TimeRangeList::trim_in(const rational &diff)
|
||||
{
|
||||
// Re-do list since we want to handle overlaps
|
||||
TimeRangeList temp = *this;
|
||||
|
||||
clear();
|
||||
|
||||
foreach (TimeRange r, temp) {
|
||||
r.set_in(r.in() + diff);
|
||||
insert(r);
|
||||
}
|
||||
}
|
||||
|
||||
void TimeRangeList::trim_out(const rational &diff)
|
||||
{
|
||||
// Re-do list since we want to handle overlaps
|
||||
TimeRangeList temp = *this;
|
||||
|
||||
clear();
|
||||
|
||||
foreach (TimeRange r, temp) {
|
||||
r.set_out(r.out() + diff);
|
||||
insert(r);
|
||||
}
|
||||
}
|
||||
|
||||
TimeRangeList TimeRangeList::Intersects(const TimeRange &range) const
|
||||
{
|
||||
TimeRangeList intersect_list;
|
||||
|
||||
for (int i=0;i<size();i++) {
|
||||
const TimeRange& compare = array_.at(i);
|
||||
|
||||
if (compare.out() <= range.in() || compare.in() >= range.out()) {
|
||||
// No intersect
|
||||
continue;
|
||||
} else {
|
||||
// Crop the time range to the range and add it to the list
|
||||
TimeRange cropped(qMax(range.in(), compare.in()),
|
||||
qMin(range.out(), compare.out()));
|
||||
|
||||
intersect_list.insert(cropped);
|
||||
}
|
||||
}
|
||||
|
||||
return intersect_list;
|
||||
}
|
||||
|
||||
uint qHash(const TimeRange &r, uint seed)
|
||||
{
|
||||
return qHash(r.in(), seed) ^ qHash(r.out(), seed);
|
||||
}
|
||||
|
||||
TimeRangeListFrameIterator::TimeRangeListFrameIterator() :
|
||||
TimeRangeListFrameIterator(TimeRangeList(), rational::NaN)
|
||||
{
|
||||
}
|
||||
|
||||
TimeRangeListFrameIterator::TimeRangeListFrameIterator(const TimeRangeList &list, const rational &timebase) :
|
||||
list_(list),
|
||||
timebase_(timebase),
|
||||
range_index_(-1),
|
||||
size_(-1),
|
||||
frame_index_(0),
|
||||
custom_range_(false)
|
||||
{
|
||||
if (!list_.isEmpty() && timebase_.isNull()) {
|
||||
qCritical() << "TimeRangeListFrameIterator created with null timebase but non-empty list, this will likely lead to infinite loops";
|
||||
}
|
||||
|
||||
UpdateIndexIfNecessary();
|
||||
}
|
||||
|
||||
rational TimeRangeListFrameIterator::Snap(const rational &r) const
|
||||
{
|
||||
return Timecode::snap_time_to_timebase(r, timebase_, Timecode::kFloor);
|
||||
}
|
||||
|
||||
bool TimeRangeListFrameIterator::GetNext(rational *out)
|
||||
{
|
||||
if (!HasNext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Output current value
|
||||
*out = current_;
|
||||
|
||||
// Determine next value by adding timebase
|
||||
current_ += timebase_;
|
||||
|
||||
// If this time is outside the current range, jump to the next one
|
||||
UpdateIndexIfNecessary();
|
||||
|
||||
// Increment frame index
|
||||
frame_index_++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimeRangeListFrameIterator::HasNext() const
|
||||
{
|
||||
return range_index_ < list_.size();
|
||||
}
|
||||
|
||||
int TimeRangeListFrameIterator::size()
|
||||
{
|
||||
if (size_ == -1) {
|
||||
// Size isn't calculated automatically for optimization, so we'll calculate it now
|
||||
size_ = 0;
|
||||
|
||||
foreach (const TimeRange &range, list_) {
|
||||
rational start = Snap(range.in());
|
||||
rational end = Timecode::snap_time_to_timebase(range.out(), timebase_, Timecode::kFloor);
|
||||
|
||||
if (end == range.out()) {
|
||||
end -= timebase_;
|
||||
}
|
||||
|
||||
int64_t start_ts = Timecode::time_to_timestamp(start, timebase_);
|
||||
int64_t end_ts = Timecode::time_to_timestamp(end, timebase_);
|
||||
|
||||
size_ += 1 + (end_ts - start_ts);
|
||||
}
|
||||
}
|
||||
|
||||
return size_;
|
||||
}
|
||||
|
||||
void TimeRangeListFrameIterator::UpdateIndexIfNecessary()
|
||||
{
|
||||
while (range_index_ < list_.size() && (range_index_ == -1 || current_ >= list_.at(range_index_).out())) {
|
||||
range_index_++;
|
||||
|
||||
if (range_index_ < list_.size()) {
|
||||
current_ = Snap(list_.at(range_index_).in());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const olive::TimeRange &r)
|
||||
{
|
||||
debug.nospace() << r.in().toDouble() << " - " << r.out().toDouble();
|
||||
return debug.space();
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const olive::TimeRangeList &r)
|
||||
{
|
||||
debug << r.internal_array();
|
||||
return debug.space();
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef TIMERANGE_H
|
||||
#define TIMERANGE_H
|
||||
|
||||
#include "rational.h"
|
||||
#include "timecodefunctions.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class TimeRange {
|
||||
public:
|
||||
TimeRange() = default;
|
||||
TimeRange(const rational& in, const rational& out);
|
||||
|
||||
const rational& in() const;
|
||||
const rational& out() const;
|
||||
const rational& length() const;
|
||||
|
||||
void set_in(const rational& in);
|
||||
void set_out(const rational& out);
|
||||
void set_range(const rational& in, const rational& out);
|
||||
|
||||
bool operator==(const TimeRange& r) const;
|
||||
bool operator!=(const TimeRange& r) const;
|
||||
|
||||
bool OverlapsWith(const TimeRange& a, bool in_inclusive = true, bool out_inclusive = true) const;
|
||||
bool Contains(const TimeRange& a, bool in_inclusive = true, bool out_inclusive = true) const;
|
||||
bool Contains(const rational& r) const;
|
||||
|
||||
TimeRange Combined(const TimeRange& a) const;
|
||||
static TimeRange Combine(const TimeRange &a, const TimeRange &b);
|
||||
TimeRange Intersected(const TimeRange& a) const;
|
||||
static TimeRange Intersect(const TimeRange &a, const TimeRange &b);
|
||||
|
||||
TimeRange operator+(const rational& rhs) const;
|
||||
TimeRange operator-(const rational& rhs) const;
|
||||
|
||||
const TimeRange& operator+=(const rational &rhs);
|
||||
const TimeRange& operator-=(const rational &rhs);
|
||||
|
||||
std::list<TimeRange> Split(const int &chunk_size) const;
|
||||
|
||||
private:
|
||||
void normalize();
|
||||
|
||||
rational in_;
|
||||
rational out_;
|
||||
rational length_;
|
||||
|
||||
};
|
||||
|
||||
class TimeRangeList {
|
||||
public:
|
||||
TimeRangeList() = default;
|
||||
|
||||
TimeRangeList(std::initializer_list<TimeRange> r) :
|
||||
array_(r)
|
||||
{
|
||||
}
|
||||
|
||||
void insert(const TimeRangeList &list_to_add);
|
||||
void insert(TimeRange range_to_add);
|
||||
|
||||
void remove(const TimeRange& remove);
|
||||
void remove(const TimeRangeList &list);
|
||||
|
||||
template <typename T>
|
||||
static void util_remove(QVector<T> *list, const TimeRange &remove)
|
||||
{
|
||||
int sz = list->size();
|
||||
|
||||
for (int i=0;i<sz;i++) {
|
||||
T& compare = (*list)[i];
|
||||
|
||||
if (remove.Contains(compare)) {
|
||||
// This element is entirely encompassed in this range, remove it
|
||||
list->removeAt(i);
|
||||
i--;
|
||||
sz--;
|
||||
} else if (compare.Contains(remove, false, false)) {
|
||||
// The remove range is within this element, only choice is to split the element into two
|
||||
T new_range = compare;
|
||||
new_range.set_in(remove.out());
|
||||
compare.set_out(remove.in());
|
||||
list->append(new_range);
|
||||
break;
|
||||
} else if (compare.in() < remove.in() && compare.out() > remove.in()) {
|
||||
// This element's out point overlaps the range's in, we'll trim it
|
||||
compare.set_out(remove.in());
|
||||
} else if (compare.in() < remove.out() && compare.out() > remove.out()) {
|
||||
// This element's in point overlaps the range's out, we'll trim it
|
||||
compare.set_in(remove.out());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(const TimeRange& range, bool in_inclusive = true, bool out_inclusive = true) const;
|
||||
|
||||
bool contains(const rational &r) const
|
||||
{
|
||||
for (const TimeRange &range : array_) {
|
||||
if (range.Contains(r)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OverlapsWith(const TimeRange& r, bool in_inclusive = true, bool out_inclusive = true) const
|
||||
{
|
||||
for (const TimeRange &range : array_) {
|
||||
if (range.OverlapsWith(r, in_inclusive, out_inclusive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return array_.isEmpty();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
array_.clear();
|
||||
}
|
||||
|
||||
int size() const
|
||||
{
|
||||
return array_.size();
|
||||
}
|
||||
|
||||
void shift(const rational& diff);
|
||||
|
||||
void trim_in(const rational& diff);
|
||||
|
||||
void trim_out(const rational& diff);
|
||||
|
||||
TimeRangeList Intersects(const TimeRange& range) const;
|
||||
|
||||
using const_iterator = QVector<TimeRange>::const_iterator;
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return array_.constBegin();
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return array_.constEnd();
|
||||
}
|
||||
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
const_iterator cend() const
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
const TimeRange& first() const
|
||||
{
|
||||
return array_.first();
|
||||
}
|
||||
|
||||
const TimeRange& last() const
|
||||
{
|
||||
return array_.last();
|
||||
}
|
||||
|
||||
const TimeRange& at(int index) const
|
||||
{
|
||||
return array_.at(index);
|
||||
}
|
||||
|
||||
const QVector<TimeRange>& internal_array() const
|
||||
{
|
||||
return array_;
|
||||
}
|
||||
|
||||
bool operator==(const TimeRangeList &rhs) const
|
||||
{
|
||||
return array_ == rhs.array_;
|
||||
}
|
||||
|
||||
private:
|
||||
QVector<TimeRange> array_;
|
||||
|
||||
};
|
||||
|
||||
class TimeRangeListFrameIterator
|
||||
{
|
||||
public:
|
||||
TimeRangeListFrameIterator();
|
||||
TimeRangeListFrameIterator(const TimeRangeList &list, const rational &timebase);
|
||||
|
||||
rational Snap(const rational &r) const;
|
||||
|
||||
bool GetNext(rational *out);
|
||||
|
||||
bool HasNext() const;
|
||||
|
||||
QVector<rational> ToVector() const
|
||||
{
|
||||
TimeRangeListFrameIterator copy(list_, timebase_);
|
||||
QVector<rational> times;
|
||||
rational r;
|
||||
while (copy.GetNext(&r)) {
|
||||
times.append(r);
|
||||
}
|
||||
return times;
|
||||
}
|
||||
|
||||
int size();
|
||||
|
||||
void reset()
|
||||
{
|
||||
*this = TimeRangeListFrameIterator();
|
||||
}
|
||||
|
||||
void insert(const TimeRange &range)
|
||||
{
|
||||
list_.insert(range);
|
||||
}
|
||||
|
||||
void insert(const TimeRangeList &list)
|
||||
{
|
||||
list_.insert(list);
|
||||
}
|
||||
|
||||
bool IsCustomRange() const
|
||||
{
|
||||
return custom_range_;
|
||||
}
|
||||
|
||||
void SetCustomRange(bool e)
|
||||
{
|
||||
custom_range_ = e;
|
||||
}
|
||||
|
||||
int frame_index() const
|
||||
{
|
||||
return frame_index_;
|
||||
}
|
||||
|
||||
private:
|
||||
void UpdateIndexIfNecessary();
|
||||
|
||||
TimeRangeList list_;
|
||||
|
||||
rational timebase_;
|
||||
|
||||
rational current_;
|
||||
|
||||
int range_index_;
|
||||
|
||||
int size_;
|
||||
|
||||
int frame_index_;
|
||||
|
||||
bool custom_range_;
|
||||
|
||||
};
|
||||
|
||||
uint qHash(const TimeRange& r, uint seed = 0);
|
||||
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const olive::TimeRange& r);
|
||||
QDebug operator<<(QDebug debug, const olive::TimeRangeList& r);
|
||||
|
||||
Q_DECLARE_METATYPE(olive::TimeRange)
|
||||
|
||||
#endif // TIMERANGE_H
|
||||
@@ -138,13 +138,13 @@ void Config::SetDefaults()
|
||||
|
||||
SetEntryInternal(QStringLiteral("AudioOutputSampleRate"), NodeValue::kInt, 48000);
|
||||
SetEntryInternal(QStringLiteral("AudioOutputChannelLayout"), NodeValue::kInt, AV_CH_LAYOUT_STEREO);
|
||||
SetEntryInternal(QStringLiteral("AudioOutputSampleFormat"), NodeValue::kInt, AudioParams::kFormatSigned16Packed);
|
||||
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::kInt, AudioParams::kFormatSigned16Packed);
|
||||
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)));
|
||||
@@ -160,8 +160,8 @@ void Config::SetDefaults()
|
||||
SetEntryInternal(QStringLiteral("DefaultSequenceAudioLayout"), NodeValue::kInt, QVariant::fromValue(static_cast<int64_t>(AV_CH_LAYOUT_STEREO)));
|
||||
|
||||
// Online/offline settings
|
||||
SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeValue::kInt, VideoParams::kFormatFloat32);
|
||||
SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeValue::kInt, VideoParams::kFormatFloat16);
|
||||
SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeValue::kInt, PixelFormat::F32);
|
||||
SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeValue::kInt, PixelFormat::F16);
|
||||
|
||||
SetEntryInternal(QStringLiteral("MarkerColor"), NodeValue::kInt, ColorCoding::kLime);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "node/value.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
+3
-3
@@ -105,7 +105,7 @@ Core *Core::instance()
|
||||
|
||||
void Core::DeclareTypesForQt()
|
||||
{
|
||||
qRegisterMetaType<rational>();
|
||||
qRegisterMetaType<olive::core::rational>();
|
||||
qRegisterMetaType<NodeValue>();
|
||||
qRegisterMetaType<NodeValueTable>();
|
||||
qRegisterMetaType<NodeValueDatabase>();
|
||||
@@ -114,8 +114,8 @@ void Core::DeclareTypesForQt()
|
||||
qRegisterMetaType<AudioParams>();
|
||||
qRegisterMetaType<NodeKeyframe::Type>();
|
||||
qRegisterMetaType<Decoder::RetrieveState>();
|
||||
qRegisterMetaType<olive::TimeRange>();
|
||||
qRegisterMetaType<Color>();
|
||||
qRegisterMetaType<olive::core::TimeRange>();
|
||||
qRegisterMetaType<olive::core::Color>();
|
||||
qRegisterMetaType<olive::AudioVisualWaveform>();
|
||||
qRegisterMetaType<olive::VideoParams>();
|
||||
qRegisterMetaType<olive::VideoParams::Interlacing>();
|
||||
|
||||
+1
-2
@@ -21,13 +21,12 @@
|
||||
#ifndef CORE_H
|
||||
#define CORE_H
|
||||
|
||||
#include <olive/core/core.h>
|
||||
#include <QFileInfoList>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "node/project/footage/footage.h"
|
||||
#include "node/project/project.h"
|
||||
#include "node/project/projectviewmodel.h"
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <QDialog>
|
||||
|
||||
#include "node/color/colormanager/colormanager.h"
|
||||
#include "render/color.h"
|
||||
#include "render/managedcolor.h"
|
||||
#include "widget/colorwheel/colorgradientwidget.h"
|
||||
#include "widget/colorwheel/colorspacechooser.h"
|
||||
|
||||
@@ -626,7 +626,7 @@ void ExportDialog::SetDefaults()
|
||||
video_tab_->height_slider()->SetDefaultValue(vp.height());
|
||||
video_tab_->SetSelectedFrameRate(vp.frame_rate());
|
||||
video_tab_->pixel_aspect_combobox()->SetPixelAspectRatio(vp.pixel_aspect_ratio());
|
||||
video_tab_->pixel_format_field()->SetPixelFormat(static_cast<VideoParams::Format>(OLIVE_CONFIG("OnlinePixelFormat").toInt()));
|
||||
video_tab_->pixel_format_field()->SetPixelFormat(static_cast<PixelFormat::Format>(OLIVE_CONFIG("OnlinePixelFormat").toInt()));
|
||||
video_tab_->interlaced_combobox()->SetInterlaceMode(vp.interlacing());
|
||||
audio_tab_->sample_rate_combobox()->SetSampleRate(ap.sample_rate());
|
||||
audio_tab_->sample_format_combobox()->SetAttemptToRestoreFormat(false);
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "common/qtutils.h"
|
||||
#include "common/rational.h"
|
||||
#include "dialog/export/codec/av1section.h"
|
||||
#include "dialog/export/codec/cineformsection.h"
|
||||
#include "dialog/export/codec/codecstack.h"
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <QGridLayout>
|
||||
|
||||
#include "core.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "widget/keyframeview/keyframeviewundo.h"
|
||||
#include "widget/nodeparamview/nodeparamviewundo.h"
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ PreferencesAudioTab::PreferencesAudioTab()
|
||||
|
||||
output_fmt_combo_ = new SampleFormatComboBox();
|
||||
output_fmt_combo_->SetPackedFormats();
|
||||
output_fmt_combo_->SetSampleFormat(static_cast<AudioParams::Format>(OLIVE_CONFIG("AudioOutputSampleFormat").toInt()));
|
||||
output_fmt_combo_->SetSampleFormat(SampleFormat::from_string(OLIVE_CONFIG("AudioOutputSampleFormat").toString().toStdString()));
|
||||
output_param_layout->addWidget(output_fmt_combo_, output_row, 1);
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ PreferencesAudioTab::PreferencesAudioTab()
|
||||
record_options_->sample_rate_combobox()->SetSampleRate(OLIVE_CONFIG("AudioRecordingSampleRate").toInt());
|
||||
record_options_->channel_layout_combobox()->SetChannelLayout(OLIVE_CONFIG("AudioRecordingChannelLayout").toULongLong());
|
||||
record_options_->bit_rate_slider()->SetValue(OLIVE_CONFIG("AudioRecordingBitRate").toInt());
|
||||
record_options_->sample_format_combobox()->SetSampleFormat(static_cast<AudioParams::Format>(OLIVE_CONFIG("AudioRecordingSampleFormat").toInt()));
|
||||
record_options_->sample_format_combobox()->SetSampleFormat(SampleFormat::from_string(OLIVE_CONFIG("AudioRecordingSampleFormat").toString().toStdString()));
|
||||
recording_layout->addWidget(record_options_);
|
||||
|
||||
connect(record_format_combo_, &ExportFormatComboBox::FormatChanged, record_options_, &ExportAudioTab::SetFormat);
|
||||
@@ -182,14 +182,14 @@ void PreferencesAudioTab::Accept(MultiUndoCommand *command)
|
||||
|
||||
OLIVE_CONFIG("AudioOutputSampleRate") = output_rate_combo_->GetSampleRate();
|
||||
OLIVE_CONFIG("AudioOutputChannelLayout") = QVariant::fromValue(output_ch_layout_combo_->GetChannelLayout());
|
||||
OLIVE_CONFIG("AudioOutputSampleFormat") = output_fmt_combo_->GetSampleFormat();
|
||||
OLIVE_CONFIG("AudioOutputSampleFormat") = QString::fromStdString(output_fmt_combo_->GetSampleFormat().to_string());
|
||||
|
||||
OLIVE_CONFIG("AudioRecordingFormat") = record_format_combo_->GetFormat();
|
||||
OLIVE_CONFIG("AudioRecordingCodec") = record_options_->GetCodec();
|
||||
OLIVE_CONFIG("AudioRecordingSampleRate") = record_options_->sample_rate_combobox()->GetSampleRate();
|
||||
OLIVE_CONFIG("AudioRecordingChannelLayout") = QVariant::fromValue(record_options_->channel_layout_combobox()->GetChannelLayout());
|
||||
OLIVE_CONFIG("AudioRecordingBitRate") = QVariant::fromValue(record_options_->bit_rate_slider()->GetValue());
|
||||
OLIVE_CONFIG("AudioRecordingSampleFormat") = record_options_->sample_format_combobox()->GetSampleFormat();
|
||||
OLIVE_CONFIG("AudioRecordingSampleFormat") = QString::fromStdString(record_options_->sample_format_combobox()->GetSampleFormat().to_string());
|
||||
|
||||
emit AudioManager::instance()->OutputParamsChanged();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "core.h"
|
||||
#include "common/channellayout.h"
|
||||
#include "common/qtutils.h"
|
||||
#include "common/rational.h"
|
||||
#include "undo/undostack.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -141,7 +140,7 @@ void SequenceDialog::accept()
|
||||
|
||||
AudioParams audio_params = AudioParams(parameter_tab_->GetSelectedAudioSampleRate(),
|
||||
parameter_tab_->GetSelectedAudioChannelLayout(),
|
||||
AudioParams::kInternalFormat);
|
||||
Sequence::kDefaultSampleFormat);
|
||||
|
||||
if (make_undoable_) {
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ void SequenceDialogParameterTab::UpdatePreviewResolutionLabel()
|
||||
{
|
||||
VideoParams test_param(GetSelectedVideoWidth(),
|
||||
GetSelectedVideoHeight(),
|
||||
VideoParams::kFormatInvalid,
|
||||
PixelFormat::INVALID,
|
||||
VideoParams::kInternalChannelCount,
|
||||
rational(1),
|
||||
VideoParams::kInterlaceNone,
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
return preview_resolution_field_->GetDivider();
|
||||
}
|
||||
|
||||
VideoParams::Format GetSelectedPreviewFormat() const
|
||||
PixelFormat GetSelectedPreviewFormat() const
|
||||
{
|
||||
return preview_format_field_->GetPixelFormat();
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
#include "common/filefunctions.h"
|
||||
#include "config/config.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/videoparams.h"
|
||||
#include "ui/icons/icons.h"
|
||||
#include "widget/menu/menu.h"
|
||||
@@ -100,7 +99,7 @@ QTreeWidgetItem* SequenceDialogPresetTab::CreateFolder(const QString &name)
|
||||
|
||||
QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &name, int width, int height, int divider)
|
||||
{
|
||||
const VideoParams::Format default_format = static_cast<VideoParams::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt());
|
||||
const PixelFormat default_format = static_cast<PixelFormat::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt());
|
||||
const bool default_autocache = false;
|
||||
QTreeWidgetItem* parent = CreateFolder(name);
|
||||
AddStandardItem(parent, std::make_shared<SequencePreset>(tr("%1 23.976 FPS").arg(name),
|
||||
@@ -163,7 +162,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na
|
||||
|
||||
QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &name, int width, int height, const rational& frame_rate, const rational &standard_par, const rational &wide_par, int divider)
|
||||
{
|
||||
const VideoParams::Format default_format = static_cast<VideoParams::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt());
|
||||
const PixelFormat default_format = static_cast<PixelFormat::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt());
|
||||
const bool default_autocache = false;
|
||||
QTreeWidgetItem* parent = CreateFolder(name);
|
||||
preset_tree_->addTopLevelItem(parent);
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#ifndef SEQUENCEPARAM_H
|
||||
#define SEQUENCEPARAM_H
|
||||
|
||||
#include <olive/core/core.h>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "common/xmlutils.h"
|
||||
#include "dialog/sequence/presetmanager.h"
|
||||
#include "render/videoparams.h"
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
int sample_rate,
|
||||
uint64_t channel_layout,
|
||||
int preview_divider,
|
||||
VideoParams::Format preview_format,
|
||||
PixelFormat preview_format,
|
||||
bool preview_autocache) :
|
||||
width_(width),
|
||||
height_(height),
|
||||
@@ -69,9 +69,9 @@ public:
|
||||
} else if (reader->name() == QStringLiteral("height")) {
|
||||
height_ = reader->readElementText().toInt();
|
||||
} else if (reader->name() == QStringLiteral("framerate")) {
|
||||
frame_rate_ = rational::fromString(reader->readElementText());
|
||||
frame_rate_ = rational::fromString(reader->readElementText().toStdString());
|
||||
} else if (reader->name() == QStringLiteral("pixelaspect")) {
|
||||
pixel_aspect_ = rational::fromString(reader->readElementText());
|
||||
pixel_aspect_ = rational::fromString(reader->readElementText().toStdString());
|
||||
} else if (reader->name() == QStringLiteral("interlacing")) {
|
||||
interlacing_ = static_cast<VideoParams::Interlacing>(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("samplerate")) {
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
} else if (reader->name() == QStringLiteral("divider")) {
|
||||
preview_divider_ = reader->readElementText().toInt();
|
||||
} else if (reader->name() == QStringLiteral("format")) {
|
||||
preview_format_ = static_cast<VideoParams::Format>(reader->readElementText().toInt());
|
||||
preview_format_ = static_cast<PixelFormat::Format>(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("autocache")) {
|
||||
preview_autocache_ = reader->readElementText().toInt();
|
||||
} else {
|
||||
@@ -95,8 +95,8 @@ public:
|
||||
writer->writeTextElement(QStringLiteral("name"), GetName());
|
||||
writer->writeTextElement(QStringLiteral("width"), QString::number(width_));
|
||||
writer->writeTextElement(QStringLiteral("height"), QString::number(height_));
|
||||
writer->writeTextElement(QStringLiteral("framerate"), frame_rate_.toString());
|
||||
writer->writeTextElement(QStringLiteral("pixelaspect"), pixel_aspect_.toString());
|
||||
writer->writeTextElement(QStringLiteral("framerate"), QString::fromStdString(frame_rate_.toString()));
|
||||
writer->writeTextElement(QStringLiteral("pixelaspect"), QString::fromStdString(pixel_aspect_.toString()));
|
||||
writer->writeTextElement(QStringLiteral("interlacing_"), QString::number(interlacing_));
|
||||
writer->writeTextElement(QStringLiteral("samplerate"), QString::number(sample_rate_));
|
||||
writer->writeTextElement(QStringLiteral("chlayout"), QString::number(channel_layout_));
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
return preview_divider_;
|
||||
}
|
||||
|
||||
VideoParams::Format preview_format() const
|
||||
PixelFormat preview_format() const
|
||||
{
|
||||
return preview_format_;
|
||||
}
|
||||
@@ -164,7 +164,7 @@ private:
|
||||
int sample_rate_;
|
||||
uint64_t channel_layout_;
|
||||
int preview_divider_;
|
||||
VideoParams::Format preview_format_;
|
||||
PixelFormat preview_format_;
|
||||
bool preview_autocache_;
|
||||
|
||||
};
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "transition.h"
|
||||
|
||||
#include "common/clamp.h"
|
||||
#include "node/block/clip/clip.h"
|
||||
#include "node/output/track/track.h"
|
||||
#include "widget/slider/rationalslider.h"
|
||||
@@ -126,7 +125,7 @@ double TransitionBlock::GetOutProgress(const double &time) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
return clamp(1.0 - (GetInternalTransitionTime(time) / out_offset().toDouble()), 0.0, 1.0);
|
||||
return std::clamp(1.0 - (GetInternalTransitionTime(time) / out_offset().toDouble()), 0.0, 1.0);
|
||||
}
|
||||
|
||||
double TransitionBlock::GetInProgress(const double &time) const
|
||||
@@ -135,7 +134,7 @@ double TransitionBlock::GetInProgress(const double &time) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
return clamp((GetInternalTransitionTime(time) - out_offset().toDouble()) / in_offset().toDouble(), 0.0, 1.0);
|
||||
return std::clamp((GetInternalTransitionTime(time) - out_offset().toDouble()) / in_offset().toDouble(), 0.0, 1.0);
|
||||
}
|
||||
|
||||
double TransitionBlock::GetInternalTransitionTime(const double &time) const
|
||||
@@ -245,7 +244,7 @@ double TransitionBlock::TransformCurve(double linear) const
|
||||
linear *= linear;
|
||||
break;
|
||||
case kLogarithmic:
|
||||
linear = qSqrt(linear);
|
||||
linear = std::sqrt(linear);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -179,9 +179,9 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou
|
||||
} else if (gizmo == rotation_gizmo_) {
|
||||
|
||||
gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().nonsquare_resolution()/2).toPointF();
|
||||
gizmo_start_angle_ = qAtan2(y - gizmo_anchor_pt_.y(), x - gizmo_anchor_pt_.x());
|
||||
gizmo_start_angle_ = std::atan2(y - gizmo_anchor_pt_.y(), x - gizmo_anchor_pt_.x());
|
||||
gizmo_last_angle_ = gizmo_start_angle_;
|
||||
gizmo_last_alt_angle_ = qAtan2(x - gizmo_anchor_pt_.x(), y - gizmo_anchor_pt_.y());
|
||||
gizmo_last_alt_angle_ = std::atan2(x - gizmo_anchor_pt_.x(), y - gizmo_anchor_pt_.y());
|
||||
gizmo_rotate_wrap_ = 0;
|
||||
gizmo_rotate_last_dir_ = kDirectionNone;
|
||||
|
||||
@@ -216,8 +216,8 @@ void TransformDistortNode::GizmoDragMove(double x, double y, const Qt::KeyboardM
|
||||
|
||||
} else if (gizmo == rotation_gizmo_) {
|
||||
|
||||
double raw_angle = qAtan2(y - gizmo_anchor_pt_.y(), x - gizmo_anchor_pt_.x());
|
||||
double alt_angle = qAtan2(x - gizmo_anchor_pt_.x(), y - gizmo_anchor_pt_.y());
|
||||
double raw_angle = std::atan2(y - gizmo_anchor_pt_.y(), x - gizmo_anchor_pt_.x());
|
||||
double alt_angle = std::atan2(x - gizmo_anchor_pt_.x(), y - gizmo_anchor_pt_.y());
|
||||
|
||||
double current_angle = raw_angle;
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "stroke.h"
|
||||
|
||||
#include "render/color.h"
|
||||
#include "widget/slider/floatslider.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -90,7 +90,7 @@ void PolygonGenerator::Retranslate()
|
||||
ShaderJob PolygonGenerator::GetGenerateJob(const NodeValueRow &value, const VideoParams ¶ms) const
|
||||
{
|
||||
VideoParams p = params;
|
||||
p.set_format(VideoParams::kFormatUnsigned8);
|
||||
p.set_format(PixelFormat::U8);
|
||||
auto job = Texture::Job(p, GenerateJob(value));
|
||||
|
||||
// Conversion to RGB
|
||||
@@ -173,7 +173,7 @@ void PolygonGenerator::UpdateGizmoPositions(const NodeValueRow &row, const NodeG
|
||||
res = globals.square_resolution();
|
||||
}
|
||||
|
||||
QPointF half_res = res.toPointF()/2;
|
||||
Imath::V2d half_res(res.x()/2, res.y()/2);
|
||||
|
||||
auto points = row[kPointsInput].toArray();
|
||||
|
||||
@@ -205,20 +205,20 @@ void PolygonGenerator::UpdateGizmoPositions(const NodeValueRow &row, const NodeG
|
||||
for (int i=0; i<pts_sz; i++) {
|
||||
const Bezier &pt = points.at(i).toBezier();
|
||||
|
||||
QPointF main = pt.ToPointF() + half_res;
|
||||
QPointF cp1 = main + pt.ControlPoint1ToPointF();
|
||||
QPointF cp2 = main + pt.ControlPoint2ToPointF();
|
||||
Imath::V2d main = pt.to_vec() + half_res;
|
||||
Imath::V2d cp1 = main + pt.control_point_1_to_vec();
|
||||
Imath::V2d cp2 = main + pt.control_point_2_to_vec();
|
||||
|
||||
gizmo_position_handles_[i]->SetPoint(main);
|
||||
gizmo_position_handles_[i]->SetPoint(QPointF(main.x, main.y));
|
||||
|
||||
gizmo_bezier_handles_[i*2]->SetPoint(cp1);
|
||||
gizmo_bezier_lines_[i*2]->SetLine(QLineF(main, cp1));
|
||||
gizmo_bezier_handles_[i*2+1]->SetPoint(cp2);
|
||||
gizmo_bezier_lines_[i*2+1]->SetLine(QLineF(main, cp2));
|
||||
gizmo_bezier_handles_[i*2]->SetPoint(QPointF(cp1.x, cp1.y));
|
||||
gizmo_bezier_lines_[i*2]->SetLine(QLineF(QPointF(main.x, main.y), QPointF(cp1.x, cp1.y)));
|
||||
gizmo_bezier_handles_[i*2+1]->SetPoint(QPointF(cp2.x, cp2.y));
|
||||
gizmo_bezier_lines_[i*2+1]->SetLine(QLineF(QPointF(main.x, main.y), QPointF(cp2.x, cp2.y)));
|
||||
}
|
||||
}
|
||||
|
||||
poly_gizmo_->SetPath(GeneratePath(points, pts_sz).translated(half_res));
|
||||
poly_gizmo_->SetPath(GeneratePath(points, pts_sz).translated(QPointF(half_res.x, half_res.y)));
|
||||
}
|
||||
|
||||
ShaderCode PolygonGenerator::GetShaderCode(const ShaderRequest &request) const
|
||||
@@ -246,9 +246,11 @@ void PolygonGenerator::GizmoDragMove(double x, double y, const Qt::KeyboardModif
|
||||
|
||||
void PolygonGenerator::AddPointToPath(QPainterPath *path, const Bezier &before, const Bezier &after)
|
||||
{
|
||||
path->cubicTo(before.ToPointF() + before.ControlPoint2ToPointF(),
|
||||
after.ToPointF() + after.ControlPoint1ToPointF(),
|
||||
after.ToPointF());
|
||||
Imath::V2d a = before.to_vec() + before.control_point_2_to_vec();
|
||||
Imath::V2d b = after.to_vec() + after.control_point_1_to_vec();
|
||||
Imath::V2d c = after.to_vec();
|
||||
|
||||
path->cubicTo(QPointF(a.x, a.y), QPointF(b.x, b.y), QPointF(c.x, c.y));
|
||||
}
|
||||
|
||||
QPainterPath PolygonGenerator::GeneratePath(const NodeValueArray &points, int size)
|
||||
@@ -257,7 +259,8 @@ QPainterPath PolygonGenerator::GeneratePath(const NodeValueArray &points, int si
|
||||
|
||||
if (!points.empty()) {
|
||||
const Bezier &first_pt = points.at(0).toBezier();
|
||||
path.moveTo(first_pt.ToPointF());
|
||||
Imath::V2d v = first_pt.to_vec();
|
||||
path.moveTo(QPointF(v.x, v.y));
|
||||
|
||||
for (int i=1; i<size; i++) {
|
||||
AddPointToPath(&path, points.at(i-1).toBezier(), points.at(i).toBezier());
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include <QPainterPath>
|
||||
|
||||
#include "common/bezier.h"
|
||||
#include "node/generator/shape/generatorwithmerge.h"
|
||||
#include "node/gizmo/line.h"
|
||||
#include "node/gizmo/path.h"
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
|
||||
#include "solid.h"
|
||||
|
||||
#include "render/color.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
const QString SolidGenerator::kColorInput = QStringLiteral("color_in");
|
||||
|
||||
@@ -20,12 +20,11 @@
|
||||
|
||||
#include "textv2.h"
|
||||
|
||||
#include <olive/core/core.h>
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QDateTime>
|
||||
#include <QTextDocument>
|
||||
|
||||
#include "common/cpuoptimize.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
#define super ShapeNodeBase
|
||||
@@ -97,7 +96,7 @@ void TextGeneratorV2::Value(const NodeValueRow &value, const NodeGlobals &global
|
||||
if (!value[kTextInput].toString().isEmpty()) {
|
||||
GenerateJob job(value);
|
||||
auto text_params = globals.vparams();
|
||||
text_params.set_format(VideoParams::kFormatFloat32);
|
||||
text_params.set_format(PixelFormat::F32);
|
||||
table->Push(NodeValue::kTexture, Texture::Job(text_params, job), this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ void TextGeneratorV3::Value(const NodeValueRow &value, const NodeGlobals &global
|
||||
TexturePtr base = value[kTextInput].toTexture();
|
||||
|
||||
VideoParams text_params = base ? base->params() : globals.vparams();
|
||||
text_params.set_format(VideoParams::kFormatUnsigned8);
|
||||
text_params.set_format(PixelFormat::U8);
|
||||
text_params.set_colorspace(project()->color_manager()->GetDefaultInputColorSpace());
|
||||
|
||||
GenerateJob job(value);
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#ifndef DRAGGABLEGIZMO_H
|
||||
#define DRAGGABLEGIZMO_H
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "gizmo.h"
|
||||
#include "node/inputdragger.h"
|
||||
#include "undo/undocommand.h"
|
||||
@@ -46,7 +45,7 @@ public:
|
||||
|
||||
explicit DraggableGizmo(QObject *parent = nullptr);
|
||||
|
||||
void DragStart(const NodeValueRow &row, double abs_x, double abs_y, const olive::rational &time);
|
||||
void DragStart(const NodeValueRow &row, double abs_x, double abs_y, const olive::core::rational &time);
|
||||
|
||||
void DragMove(double x, double y, const Qt::KeyboardModifiers &modifiers);
|
||||
|
||||
@@ -67,7 +66,7 @@ public:
|
||||
void SetDragValueBehavior(DragValueBehavior d) { drag_value_behavior_ = d; }
|
||||
|
||||
signals:
|
||||
void HandleStart(const olive::NodeValueRow &row, double x, double y, const olive::rational &time);
|
||||
void HandleStart(const olive::NodeValueRow &row, double x, double y, const olive::core::rational &time);
|
||||
|
||||
void HandleMovement(double x, double y, const Qt::KeyboardModifiers &modifiers);
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
#include <QVector2D>
|
||||
|
||||
#include "common/timerange.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/loopmode.h"
|
||||
#include "render/videoparams.h"
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#ifndef NODEINPUTDRAGGER_H
|
||||
#define NODEINPUTDRAGGER_H
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "node/keyframe.h"
|
||||
#include "node/param.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "inputimmediate.h"
|
||||
|
||||
#include "common/bezier.h"
|
||||
#include "common/lerp.h"
|
||||
#include "common/tohex.h"
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#ifndef NODEINPUTIMMEDIATE_H
|
||||
#define NODEINPUTIMMEDIATE_H
|
||||
|
||||
#include "common/timerange.h"
|
||||
#include "common/xmlutils.h"
|
||||
#include "node/keyframe.h"
|
||||
#include "node/value.h"
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include <QPointF>
|
||||
#include <QVariant>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "common/timerange.h"
|
||||
#include "node/param.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -23,10 +23,8 @@
|
||||
#include <QMatrix4x4>
|
||||
#include <QVector2D>
|
||||
|
||||
#include "common/cpuoptimize.h"
|
||||
#include "common/tohex.h"
|
||||
#include "node/distort/transform/transformdistortnode.h"
|
||||
#include "render/color.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -596,7 +594,7 @@ T MathNodeBase::PerformAll(Operation operation, T a, U b)
|
||||
case kOpDivide:
|
||||
return a / b;
|
||||
case kOpPower:
|
||||
return qPow(a, b);
|
||||
return std::pow(a, b);
|
||||
}
|
||||
|
||||
return a;
|
||||
|
||||
@@ -83,22 +83,22 @@ void TrigonometryNode::Value(const NodeValueRow &value, const NodeGlobals &globa
|
||||
|
||||
switch (static_cast<Operation>(GetStandardValue(kMethodIn).toInt())) {
|
||||
case kOpSine:
|
||||
x = qSin(x);
|
||||
x = std::sin(x);
|
||||
break;
|
||||
case kOpCosine:
|
||||
x = qCos(x);
|
||||
x = std::cos(x);
|
||||
break;
|
||||
case kOpTangent:
|
||||
x = qTan(x);
|
||||
x = std::tan(x);
|
||||
break;
|
||||
case kOpArcSine:
|
||||
x = qAsin(x);
|
||||
x = std::asin(x);
|
||||
break;
|
||||
case kOpArcCosine:
|
||||
x = qAcos(x);
|
||||
x = std::acos(x);
|
||||
break;
|
||||
case kOpArcTangent:
|
||||
x = qAtan(x);
|
||||
x = std::atan(x);
|
||||
break;
|
||||
case kOpHypSine:
|
||||
x = std::sinh(x);
|
||||
|
||||
+13
-16
@@ -25,7 +25,6 @@
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
||||
#include "common/bezier.h"
|
||||
#include "common/lerp.h"
|
||||
#include "core.h"
|
||||
#include "config/config.h"
|
||||
@@ -163,7 +162,7 @@ QLinearGradient Node::gradient_color(qreal top, qreal bottom) const
|
||||
grad.setStart(0, top);
|
||||
grad.setFinalStop(0, bottom);
|
||||
|
||||
QColor c = color().toQColor();
|
||||
QColor c = QtUtils::toQColor(color());
|
||||
|
||||
grad.setColorAt(0.0, c.lighter());
|
||||
grad.setColorAt(1.0, c);
|
||||
@@ -176,7 +175,7 @@ QBrush Node::brush(qreal top, qreal bottom) const
|
||||
if (OLIVE_CONFIG("UseGradients").toBool()) {
|
||||
return gradient_color(top, bottom);
|
||||
} else {
|
||||
return color().toQColor();
|
||||
return QtUtils::toQColor(color());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,31 +483,29 @@ QVariant Node::GetSplitValueAtTimeOnTrack(const QString &input, const rational &
|
||||
|
||||
// Perform a cubic bezier with two control points
|
||||
interpolated = Bezier::CubicXtoY(time.toDouble(),
|
||||
QPointF(before->time().toDouble(), before_val),
|
||||
QPointF(before->time().toDouble() + before->valid_bezier_control_out().x(), before_val + before->valid_bezier_control_out().y()),
|
||||
QPointF(after->time().toDouble() + after->valid_bezier_control_in().x(), after_val + after->valid_bezier_control_in().y()),
|
||||
QPointF(after->time().toDouble(), after_val));
|
||||
Imath::V2d(before->time().toDouble(), before_val),
|
||||
Imath::V2d(before->time().toDouble() + before->valid_bezier_control_out().x(), before_val + before->valid_bezier_control_out().y()),
|
||||
Imath::V2d(after->time().toDouble() + after->valid_bezier_control_in().x(), after_val + after->valid_bezier_control_in().y()),
|
||||
Imath::V2d(after->time().toDouble(), after_val));
|
||||
|
||||
} else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) {
|
||||
// Perform a quadratic bezier with only one control point
|
||||
|
||||
QPointF control_point;
|
||||
Imath::V2d control_point;
|
||||
|
||||
if (before->type() == NodeKeyframe::kBezier) {
|
||||
control_point = before->valid_bezier_control_out();
|
||||
control_point.setX(control_point.x() + before->time().toDouble());
|
||||
control_point.setY(control_point.y() + before_val);
|
||||
control_point.x = (before->valid_bezier_control_out().x() + before->time().toDouble());
|
||||
control_point.y = (before->valid_bezier_control_out().y() + before_val);
|
||||
} else {
|
||||
control_point = after->valid_bezier_control_in();
|
||||
control_point.setX(control_point.x() + after->time().toDouble());
|
||||
control_point.setY(control_point.y() + after_val);
|
||||
control_point.x = (after->valid_bezier_control_in().x() + after->time().toDouble());
|
||||
control_point.y = (after->valid_bezier_control_in().y() + after_val);
|
||||
}
|
||||
|
||||
// Interpolate value using quadratic beziers
|
||||
interpolated = Bezier::QuadraticXtoY(time.toDouble(),
|
||||
QPointF(before->time().toDouble(), before_val),
|
||||
Imath::V2d(before->time().toDouble(), before_val),
|
||||
control_point,
|
||||
QPointF(after->time().toDouble(), after_val));
|
||||
Imath::V2d(after->time().toDouble(), after_val));
|
||||
|
||||
} else {
|
||||
// To have arrived here, the keyframes must both be linear
|
||||
|
||||
+3
-7
@@ -29,16 +29,12 @@
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#include "codec/frame.h"
|
||||
#include "codec/samplebuffer.h"
|
||||
#include "common/rational.h"
|
||||
#include "common/timerange.h"
|
||||
#include "common/xmlutils.h"
|
||||
#include "node/gizmo/draggable.h"
|
||||
#include "node/globals.h"
|
||||
#include "node/keyframe.h"
|
||||
#include "node/inputimmediate.h"
|
||||
#include "node/param.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/audioplaybackcache.h"
|
||||
#include "render/audiowaveformcache.h"
|
||||
#include "render/framehashcache.h"
|
||||
@@ -1229,7 +1225,7 @@ protected:
|
||||
}
|
||||
|
||||
protected slots:
|
||||
virtual void GizmoDragStart(const olive::NodeValueRow &row, double x, double y, const olive::rational &time){}
|
||||
virtual void GizmoDragStart(const olive::NodeValueRow &row, double x, double y, const olive::core::rational &time){}
|
||||
|
||||
virtual void GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers){}
|
||||
|
||||
@@ -1379,8 +1375,8 @@ private:
|
||||
|
||||
QVector<Node*> GetDependenciesInternal(bool traverse, bool exclusive_only) const;
|
||||
|
||||
void ParameterValueChanged(const QString &input, int element, const olive::TimeRange &range);
|
||||
void ParameterValueChanged(const NodeInput& input, const olive::TimeRange &range)
|
||||
void ParameterValueChanged(const QString &input, int element, const olive::core::TimeRange &range);
|
||||
void ParameterValueChanged(const NodeInput& input, const olive::core::TimeRange &range)
|
||||
{
|
||||
ParameterValueChanged(input.input(), input.element(), range);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ const QString ViewerOutput::kSubtitleParamsInput = QStringLiteral("subtitle_para
|
||||
const QString ViewerOutput::kTextureInput = QStringLiteral("tex_in");
|
||||
const QString ViewerOutput::kSamplesInput = QStringLiteral("samples_in");
|
||||
|
||||
const SampleFormat ViewerOutput::kDefaultSampleFormat = SampleFormat::F32P;
|
||||
|
||||
#define super Node
|
||||
|
||||
ViewerOutput::ViewerOutput(bool create_buffer_inputs, bool create_default_streams) :
|
||||
@@ -116,7 +118,7 @@ QString ViewerOutput::duration() const
|
||||
return QString();
|
||||
} else {
|
||||
// Return time transformed to timecode
|
||||
return Timecode::time_to_timecode(GetLength(), using_timebase, using_display);
|
||||
return QString::fromStdString(Timecode::time_to_timecode(GetLength(), using_timebase, using_display));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,16 +208,16 @@ void ViewerOutput::set_default_parameters()
|
||||
width,
|
||||
height,
|
||||
OLIVE_CONFIG("DefaultSequenceFrameRate").value<rational>(),
|
||||
static_cast<VideoParams::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt()),
|
||||
static_cast<PixelFormat::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt()),
|
||||
VideoParams::kInternalChannelCount,
|
||||
OLIVE_CONFIG("DefaultSequencePixelAspect").value<rational>(),
|
||||
OLIVE_CONFIG("DefaultSequenceInterlacing").value<VideoParams::Interlacing>(),
|
||||
VideoParams::generate_auto_divider(width, height)
|
||||
));
|
||||
SetAudioParams(AudioParams(
|
||||
OLIVE_CONFIG("DefaultSequenceAudioFrequency").toInt(),
|
||||
OLIVE_CONFIG("DefaultSequenceAudioLayout").toULongLong(),
|
||||
AudioParams::kInternalFormat
|
||||
OLIVE_CONFIG("DefaultSequenceAudioFrequency").toInt(),
|
||||
OLIVE_CONFIG("DefaultSequenceAudioLayout").toULongLong(),
|
||||
kDefaultSampleFormat
|
||||
));
|
||||
}
|
||||
|
||||
@@ -505,7 +507,7 @@ void ViewerOutput::set_parameters_from_footage(const QVector<ViewerOutput *> foo
|
||||
SetVideoParams(VideoParams(s.width(),
|
||||
s.height(),
|
||||
using_timebase,
|
||||
static_cast<VideoParams::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt()),
|
||||
static_cast<PixelFormat::Format>(OLIVE_CONFIG("OfflinePixelFormat").toInt()),
|
||||
VideoParams::kInternalChannelCount,
|
||||
s.pixel_aspect_ratio(),
|
||||
s.interlacing(),
|
||||
@@ -518,7 +520,7 @@ void ViewerOutput::set_parameters_from_footage(const QVector<ViewerOutput *> foo
|
||||
|
||||
if (!audio_streams.isEmpty()) {
|
||||
const AudioParams& s = audio_streams.first();
|
||||
SetAudioParams(AudioParams(s.sample_rate(), s.channel_layout(), AudioParams::kInternalFormat));
|
||||
SetAudioParams(AudioParams(s.sample_rate(), s.channel_layout(), kDefaultSampleFormat));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,8 @@
|
||||
#define VIEWER_H
|
||||
|
||||
#include "codec/encoder.h"
|
||||
#include "common/rational.h"
|
||||
#include "node/node.h"
|
||||
#include "node/output/track/track.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/audioplaybackcache.h"
|
||||
#include "render/framehashcache.h"
|
||||
#include "render/subtitleparams.h"
|
||||
@@ -201,6 +199,8 @@ public:
|
||||
static const QString kTextureInput;
|
||||
static const QString kSamplesInput;
|
||||
|
||||
static const SampleFormat kDefaultSampleFormat;
|
||||
|
||||
signals:
|
||||
void FrameRateChanged(const rational&);
|
||||
|
||||
|
||||
+2
-2
@@ -170,12 +170,12 @@ int NodeInput::GetArraySize() const
|
||||
|
||||
uint qHash(const NodeInput &i)
|
||||
{
|
||||
return qHash(i.node()) ^ qHash(i.input()) ^ qHash(i.element());
|
||||
return qHash(i.node()) ^ qHash(i.input()) ^ ::qHash(i.element());
|
||||
}
|
||||
|
||||
uint qHash(const NodeKeyframeTrackReference &i)
|
||||
{
|
||||
return qHash(i.input()) & qHash(i.track());
|
||||
return qHash(i.input()) & ::qHash(i.track());
|
||||
}
|
||||
|
||||
uint qHash(const NodeInputPair &i)
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "value.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "codec/decoder.h"
|
||||
#include "common/clamp.h"
|
||||
#include "common/filefunctions.h"
|
||||
#include "common/qtutils.h"
|
||||
#include "common/xmlutils.h"
|
||||
@@ -352,7 +351,7 @@ rational Footage::AdjustTimeByLoopMode(rational time, LoopMode loop_mode, const
|
||||
break;
|
||||
case LoopMode::kLoopModeClamp:
|
||||
// Clamp footage time to length
|
||||
time = clamp(time, rational(0), length - timebase);
|
||||
time = std::clamp(time, rational(0), length - timebase);
|
||||
break;
|
||||
case LoopMode::kLoopModeLoop:
|
||||
// Loop footage time around job length
|
||||
|
||||
@@ -21,14 +21,13 @@
|
||||
#ifndef FOOTAGE_H
|
||||
#define FOOTAGE_H
|
||||
|
||||
#include <olive/core/core.h>
|
||||
#include <QList>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "codec/decoder.h"
|
||||
#include "common/rational.h"
|
||||
#include "footagedescription.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/cancelatom.h"
|
||||
#include "render/videoparams.h"
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#include "common/xmlutils.h"
|
||||
#include "node/project/serializer/typeserializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -74,8 +75,7 @@ bool FootageDescription::Load(const QString &filename)
|
||||
vp.Load(&reader);
|
||||
AddVideoStream(vp);
|
||||
} else if (reader.name() == QStringLiteral("audio")) {
|
||||
AudioParams ap;
|
||||
ap.Load(&reader);
|
||||
AudioParams ap = TypeSerializer::LoadAudioParams(&reader);
|
||||
AddAudioStream(ap);
|
||||
} else if (reader.name() == QStringLiteral("subtitle")) {
|
||||
SubtitleParams sp;
|
||||
@@ -136,7 +136,7 @@ bool FootageDescription::Save(const QString &filename) const
|
||||
|
||||
foreach (const AudioParams& ap, audio_streams_) {
|
||||
writer.writeStartElement(QStringLiteral("audio"));
|
||||
ap.Save(&writer);
|
||||
TypeSerializer::SaveAudioParams(&writer, ap);
|
||||
writer.writeEndElement(); // audio
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define FOOTAGEDESCRIPTION_H
|
||||
|
||||
#include "node/output/track/track.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/subtitleparams.h"
|
||||
#include "render/videoparams.h"
|
||||
|
||||
|
||||
@@ -29,5 +29,9 @@ set(OLIVE_SOURCES
|
||||
node/project/serializer/serializer211228.h
|
||||
node/project/serializer/serializer220403.cpp
|
||||
node/project/serializer/serializer220403.h
|
||||
|
||||
node/project/serializer/typeserializer.cpp
|
||||
node/project/serializer/typeserializer.h
|
||||
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -21,10 +21,11 @@
|
||||
#ifndef PROJECTSERIALIZER_H
|
||||
#define PROJECTSERIALIZER_H
|
||||
|
||||
#include <QIODevice>
|
||||
#include <vector>
|
||||
|
||||
#include "common/define.h"
|
||||
#include "node/project/project.h"
|
||||
#include "typeserializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
|
||||
@@ -328,8 +328,7 @@ void ProjectSerializer210528::LoadImmediate(QXmlStreamReader *reader, Node *node
|
||||
vp.Load(reader);
|
||||
value_on_track = QVariant::fromValue(vp);
|
||||
} else if (data_type == NodeValue::kAudioParams) {
|
||||
AudioParams ap;
|
||||
ap.Load(reader);
|
||||
AudioParams ap = TypeSerializer::LoadAudioParams(reader);
|
||||
value_on_track = QVariant::fromValue(ap);
|
||||
} else {
|
||||
QString value_text = reader->readElementText();
|
||||
@@ -378,7 +377,7 @@ void ProjectSerializer210528::LoadImmediate(QXmlStreamReader *reader, Node *node
|
||||
if (attr.name() == QStringLiteral("input")) {
|
||||
key_input = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("time")) {
|
||||
key_time = rational::fromString(attr.value().toString());
|
||||
key_time = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("type")) {
|
||||
key_type = static_cast<NodeKeyframe::Type>(attr.value().toInt());
|
||||
} else if (attr.name() == QStringLiteral("inhandlex")) {
|
||||
@@ -575,9 +574,9 @@ void ProjectSerializer210528::LoadWorkArea(QXmlStreamReader *reader, TimelineWor
|
||||
if (attr.name() == QStringLiteral("enabled")) {
|
||||
workarea->set_enabled(attr.value() != QStringLiteral("0"));
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
range_in = rational::fromString(attr.value().toString());
|
||||
range_in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
range_out = rational::fromString(attr.value().toString());
|
||||
range_out = rational::fromString(attr.value().toString().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,9 +600,9 @@ void ProjectSerializer210528::LoadMarkerList(QXmlStreamReader *reader, TimelineM
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
name = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
in = rational::fromString(attr.value().toString());
|
||||
in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
out = rational::fromString(attr.value().toString());
|
||||
out = rational::fromString(attr.value().toString().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -325,8 +325,7 @@ void ProjectSerializer210907::LoadImmediate(QXmlStreamReader *reader, Node *node
|
||||
vp.Load(reader);
|
||||
value_on_track = QVariant::fromValue(vp);
|
||||
} else if (data_type == NodeValue::kAudioParams) {
|
||||
AudioParams ap;
|
||||
ap.Load(reader);
|
||||
AudioParams ap = TypeSerializer::LoadAudioParams(reader);
|
||||
value_on_track = QVariant::fromValue(ap);
|
||||
} else {
|
||||
QString value_text = reader->readElementText();
|
||||
@@ -375,7 +374,7 @@ void ProjectSerializer210907::LoadImmediate(QXmlStreamReader *reader, Node *node
|
||||
if (attr.name() == QStringLiteral("input")) {
|
||||
key_input = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("time")) {
|
||||
key_time = rational::fromString(attr.value().toString());
|
||||
key_time = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("type")) {
|
||||
key_type = static_cast<NodeKeyframe::Type>(attr.value().toInt());
|
||||
} else if (attr.name() == QStringLiteral("inhandlex")) {
|
||||
@@ -567,9 +566,9 @@ void ProjectSerializer210907::LoadWorkArea(QXmlStreamReader *reader, TimelineWor
|
||||
if (attr.name() == QStringLiteral("enabled")) {
|
||||
workarea->set_enabled(attr.value() != QStringLiteral("0"));
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
range_in = rational::fromString(attr.value().toString());
|
||||
range_in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
range_out = rational::fromString(attr.value().toString());
|
||||
range_out = rational::fromString(attr.value().toString().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,9 +592,9 @@ void ProjectSerializer210907::LoadMarkerList(QXmlStreamReader *reader, TimelineM
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
name = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
in = rational::fromString(attr.value().toString());
|
||||
in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
out = rational::fromString(attr.value().toString());
|
||||
out = rational::fromString(attr.value().toString().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -375,8 +375,7 @@ void ProjectSerializer211228::LoadImmediate(QXmlStreamReader *reader, Node *node
|
||||
vp.Load(reader);
|
||||
value_on_track = QVariant::fromValue(vp);
|
||||
} else if (data_type == NodeValue::kAudioParams) {
|
||||
AudioParams ap;
|
||||
ap.Load(reader);
|
||||
AudioParams ap = TypeSerializer::LoadAudioParams(reader);
|
||||
value_on_track = QVariant::fromValue(ap);
|
||||
} else {
|
||||
QString value_text = reader->readElementText();
|
||||
@@ -425,7 +424,7 @@ void ProjectSerializer211228::LoadImmediate(QXmlStreamReader *reader, Node *node
|
||||
if (attr.name() == QStringLiteral("input")) {
|
||||
key_input = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("time")) {
|
||||
key_time = rational::fromString(attr.value().toString());
|
||||
key_time = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("type")) {
|
||||
key_type = static_cast<NodeKeyframe::Type>(attr.value().toInt());
|
||||
} else if (attr.name() == QStringLiteral("inhandlex")) {
|
||||
@@ -617,9 +616,9 @@ void ProjectSerializer211228::LoadWorkArea(QXmlStreamReader *reader, TimelineWor
|
||||
if (attr.name() == QStringLiteral("enabled")) {
|
||||
workarea->set_enabled(attr.value() != QStringLiteral("0"));
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
range_in = rational::fromString(attr.value().toString());
|
||||
range_in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
range_out = rational::fromString(attr.value().toString());
|
||||
range_out = rational::fromString(attr.value().toString().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -643,9 +642,9 @@ void ProjectSerializer211228::LoadMarkerList(QXmlStreamReader *reader, TimelineM
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
name = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
in = rational::fromString(attr.value().toString());
|
||||
in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
out = rational::fromString(attr.value().toString());
|
||||
out = rational::fromString(attr.value().toString().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -774,8 +774,7 @@ void ProjectSerializer220403::LoadImmediate(QXmlStreamReader *reader, Node *node
|
||||
vp.Load(reader);
|
||||
value_on_track = QVariant::fromValue(vp);
|
||||
} else if (data_type == NodeValue::kAudioParams) {
|
||||
AudioParams ap;
|
||||
ap.Load(reader);
|
||||
AudioParams ap = TypeSerializer::LoadAudioParams(reader);
|
||||
value_on_track = QVariant::fromValue(ap);
|
||||
} else {
|
||||
QString value_text = reader->readElementText();
|
||||
@@ -857,7 +856,7 @@ void ProjectSerializer220403::SaveImmediate(QXmlStreamWriter *writer, Node *node
|
||||
if (data_type == NodeValue::kVideoParams) {
|
||||
v.value<VideoParams>().Save(writer);
|
||||
} else if (data_type == NodeValue::kAudioParams) {
|
||||
v.value<AudioParams>().Save(writer);
|
||||
TypeSerializer::SaveAudioParams(writer, v.value<AudioParams>());
|
||||
} else {
|
||||
writer->writeCharacters(NodeValue::ValueToString(data_type, v, true));
|
||||
}
|
||||
@@ -909,7 +908,7 @@ void ProjectSerializer220403::LoadKeyframe(QXmlStreamReader *reader, NodeKeyfram
|
||||
if (attr.name() == QStringLiteral("input")) {
|
||||
key_input = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("time")) {
|
||||
key->set_time(rational::fromString(attr.value().toString()));
|
||||
key->set_time(rational::fromString(attr.value().toString().toStdString()));
|
||||
} else if (attr.name() == QStringLiteral("type")) {
|
||||
key->set_type_no_bezier_adj(static_cast<NodeKeyframe::Type>(attr.value().toInt()));
|
||||
} else if (attr.name() == QStringLiteral("inhandlex")) {
|
||||
@@ -932,7 +931,7 @@ void ProjectSerializer220403::LoadKeyframe(QXmlStreamReader *reader, NodeKeyfram
|
||||
void ProjectSerializer220403::SaveKeyframe(QXmlStreamWriter *writer, NodeKeyframe *key, NodeValue::Type data_type) const
|
||||
{
|
||||
writer->writeAttribute(QStringLiteral("input"), key->input());
|
||||
writer->writeAttribute(QStringLiteral("time"), key->time().toString());
|
||||
writer->writeAttribute(QStringLiteral("time"), QString::fromStdString(key->time().toString()));
|
||||
writer->writeAttribute(QStringLiteral("type"), QString::number(key->type()));
|
||||
writer->writeAttribute(QStringLiteral("inhandlex"), QString::number(key->bezier_control_in().x()));
|
||||
writer->writeAttribute(QStringLiteral("inhandley"), QString::number(key->bezier_control_in().y()));
|
||||
@@ -1214,9 +1213,9 @@ void ProjectSerializer220403::LoadMarker(QXmlStreamReader *reader, TimelineMarke
|
||||
if (attr.name() == QStringLiteral("name")) {
|
||||
marker->set_name(attr.value().toString());
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
in = rational::fromString(attr.value().toString());
|
||||
in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
out = rational::fromString(attr.value().toString());
|
||||
out = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("color")) {
|
||||
marker->set_color(attr.value().toInt());
|
||||
}
|
||||
@@ -1231,8 +1230,8 @@ void ProjectSerializer220403::LoadMarker(QXmlStreamReader *reader, TimelineMarke
|
||||
void ProjectSerializer220403::SaveMarker(QXmlStreamWriter *writer, TimelineMarker *marker) const
|
||||
{
|
||||
writer->writeAttribute(QStringLiteral("name"), marker->name());
|
||||
writer->writeAttribute(QStringLiteral("in"), marker->time().in().toString());
|
||||
writer->writeAttribute(QStringLiteral("out"), marker->time().out().toString());
|
||||
writer->writeAttribute(QStringLiteral("in"), QString::fromStdString(marker->time().in().toString()));
|
||||
writer->writeAttribute(QStringLiteral("out"), QString::fromStdString(marker->time().out().toString()));
|
||||
writer->writeAttribute(QStringLiteral("color"), QString::number(marker->color()));
|
||||
}
|
||||
|
||||
@@ -1245,9 +1244,9 @@ void ProjectSerializer220403::LoadWorkArea(QXmlStreamReader *reader, TimelineWor
|
||||
if (attr.name() == QStringLiteral("enabled")) {
|
||||
workarea->set_enabled(attr.value() != QStringLiteral("0"));
|
||||
} else if (attr.name() == QStringLiteral("in")) {
|
||||
range_in = rational::fromString(attr.value().toString());
|
||||
range_in = rational::fromString(attr.value().toString().toStdString());
|
||||
} else if (attr.name() == QStringLiteral("out")) {
|
||||
range_out = rational::fromString(attr.value().toString());
|
||||
range_out = rational::fromString(attr.value().toString().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1263,8 +1262,8 @@ void ProjectSerializer220403::LoadWorkArea(QXmlStreamReader *reader, TimelineWor
|
||||
void ProjectSerializer220403::SaveWorkArea(QXmlStreamWriter *writer, TimelineWorkArea *workarea) const
|
||||
{
|
||||
writer->writeAttribute(QStringLiteral("enabled"), QString::number(workarea->enabled()));
|
||||
writer->writeAttribute(QStringLiteral("in"), workarea->in().toString());
|
||||
writer->writeAttribute(QStringLiteral("out"), workarea->out().toString());
|
||||
writer->writeAttribute(QStringLiteral("in"), QString::fromStdString(workarea->in().toString()));
|
||||
writer->writeAttribute(QStringLiteral("out"), QString::fromStdString(workarea->out().toString()));
|
||||
}
|
||||
|
||||
void ProjectSerializer220403::LoadMarkerList(QXmlStreamReader *reader, TimelineMarkerList *markers) const
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "typeserializer.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
AudioParams TypeSerializer::LoadAudioParams(QXmlStreamReader *reader)
|
||||
{
|
||||
AudioParams a;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("samplerate")) {
|
||||
a.set_sample_rate(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("channellayout")) {
|
||||
a.set_channel_layout(reader->readElementText().toULongLong());
|
||||
} else if (reader->name() == QStringLiteral("format")) {
|
||||
a.set_format(SampleFormat::from_string(reader->readElementText().toStdString()));
|
||||
} else if (reader->name() == QStringLiteral("enabled")) {
|
||||
a.set_enabled(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("streamindex")) {
|
||||
a.set_stream_index(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("duration")) {
|
||||
a.set_duration(reader->readElementText().toLongLong());
|
||||
} else if (reader->name() == QStringLiteral("timebase")) {
|
||||
a.set_time_base(rational::fromString(reader->readElementText().toStdString()));
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void TypeSerializer::SaveAudioParams(QXmlStreamWriter *writer, const AudioParams &a)
|
||||
{
|
||||
writer->writeTextElement(QStringLiteral("samplerate"), QString::number(a.sample_rate()));
|
||||
writer->writeTextElement(QStringLiteral("channellayout"), QString::number(a.channel_layout()));
|
||||
writer->writeTextElement(QStringLiteral("format"), QString::fromStdString(a.format().to_string()));
|
||||
writer->writeTextElement(QStringLiteral("enabled"), QString::number(a.enabled()));
|
||||
writer->writeTextElement(QStringLiteral("streamindex"), QString::number(a.stream_index()));
|
||||
writer->writeTextElement(QStringLiteral("duration"), QString::number(a.duration()));
|
||||
writer->writeTextElement(QStringLiteral("timebase"), QString::fromStdString(a.time_base().toString()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
Copyright (C) 2023 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -18,13 +18,29 @@
|
||||
|
||||
***/
|
||||
|
||||
#ifndef CPUOPTIMIZE_H
|
||||
#define CPUOPTIMIZE_H
|
||||
#ifndef TYPESERIALIZER_H
|
||||
#define TYPESERIALIZER_H
|
||||
|
||||
#if defined(Q_PROCESSOR_X86)
|
||||
#include <xmmintrin.h>
|
||||
#elif defined(Q_PROCESSOR_ARM)
|
||||
#include <sse2neon.h>
|
||||
#endif
|
||||
#include <olive/core/core.h>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#endif // CPUOPTIMIZE_H
|
||||
#include "common/xmlutils.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
using namespace core;
|
||||
|
||||
class TypeSerializer
|
||||
{
|
||||
public:
|
||||
TypeSerializer() = default;
|
||||
|
||||
static AudioParams LoadAudioParams(QXmlStreamReader *reader);
|
||||
static void SaveAudioParams(QXmlStreamWriter *writer, const AudioParams &a);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TYPESERIALIZER_H
|
||||
+2
-5
@@ -26,12 +26,9 @@
|
||||
#include <QVector3D>
|
||||
#include <QVector4D>
|
||||
|
||||
#include "common/bezier.h"
|
||||
#include "common/tohex.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/subtitleparams.h"
|
||||
#include "render/videoparams.h"
|
||||
#include "render/color.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -72,7 +69,7 @@ QString NodeValue::ValueToString(Type data_type, const QVariant &value, bool val
|
||||
QString::number(b.cp2_x()),
|
||||
QString::number(b.cp2_y()));
|
||||
} else if (data_type == kRational) {
|
||||
return value.value<rational>().toString();
|
||||
return QString::fromStdString(value.value<rational>().toString());
|
||||
} else if (data_type == kTexture
|
||||
|| data_type == kSamples
|
||||
|| data_type == kNone) {
|
||||
@@ -245,7 +242,7 @@ QVariant NodeValue::StringToValue(Type data_type, const QString &string, bool va
|
||||
} else if (data_type == kInt) {
|
||||
return QVariant::fromValue(string.toLongLong());
|
||||
} else if (data_type == kRational) {
|
||||
return QVariant::fromValue(rational::fromString(string));
|
||||
return QVariant::fromValue(rational::fromString(string.toStdString()));
|
||||
} else {
|
||||
return string;
|
||||
}
|
||||
|
||||
+3
-5
@@ -26,10 +26,8 @@
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
|
||||
#include "codec/samplebuffer.h"
|
||||
#include "common/bezier.h"
|
||||
#include "common/qtutils.h"
|
||||
#include "node/splitvalue.h"
|
||||
#include "render/color.h"
|
||||
#include "render/texture.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -338,9 +336,9 @@ public:
|
||||
bool toBool() const { return value<bool>(); }
|
||||
double toDouble() const { return value<double>(); }
|
||||
int64_t toInt() const { return value<int64_t>(); }
|
||||
rational toRational() const { return value<rational>(); }
|
||||
rational toRational() const { return value<olive::core::rational>(); }
|
||||
QString toString() const { return value<QString>(); }
|
||||
Color toColor() const { return value<Color>(); }
|
||||
Color toColor() const { return value<olive::core::Color>(); }
|
||||
QMatrix4x4 toMatrix() const { return value<QMatrix4x4>(); }
|
||||
VideoParams toVideoParams() const { return value<VideoParams>(); }
|
||||
AudioParams toAudioParams() const { return value<AudioParams>(); }
|
||||
|
||||
@@ -20,15 +20,11 @@ add_subdirectory(opengl)
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
render/audioparams.cpp
|
||||
render/audioparams.h
|
||||
render/audioplaybackcache.cpp
|
||||
render/audioplaybackcache.h
|
||||
render/audiowaveformcache.cpp
|
||||
render/audiowaveformcache.h
|
||||
render/cancelatom.h
|
||||
render/color.cpp
|
||||
render/color.h
|
||||
render/colorprocessor.cpp
|
||||
render/colorprocessor.h
|
||||
render/colorprocessorcache.h
|
||||
|
||||
@@ -1,358 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "audioparams.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "common/xmlutils.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
const QVector<int> AudioParams::kSupportedSampleRates = {
|
||||
8000, // 8000 Hz
|
||||
11025, // 11025 Hz
|
||||
16000, // 16000 Hz
|
||||
22050, // 22050 Hz
|
||||
24000, // 24000 Hz
|
||||
32000, // 32000 Hz
|
||||
44100, // 44100 Hz
|
||||
48000, // 48000 Hz
|
||||
88200, // 88200 Hz
|
||||
96000 // 96000 Hz
|
||||
};
|
||||
|
||||
const QVector<uint64_t> AudioParams::kSupportedChannelLayouts = {
|
||||
AV_CH_LAYOUT_MONO,
|
||||
AV_CH_LAYOUT_STEREO,
|
||||
AV_CH_LAYOUT_2_1,
|
||||
AV_CH_LAYOUT_5POINT1,
|
||||
AV_CH_LAYOUT_7POINT1
|
||||
};
|
||||
|
||||
const AudioParams::Format AudioParams::kInternalFormat = AudioParams::kFormatFloat32Planar;
|
||||
|
||||
bool AudioParams::operator==(const AudioParams &other) const
|
||||
{
|
||||
return (format() == other.format()
|
||||
&& sample_rate() == other.sample_rate()
|
||||
&& time_base() == other.time_base()
|
||||
&& channel_layout() == other.channel_layout());
|
||||
}
|
||||
|
||||
bool AudioParams::operator!=(const AudioParams &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
qint64 AudioParams::time_to_bytes(const double &time) const
|
||||
{
|
||||
return time_to_bytes_per_channel(time) * channel_count();
|
||||
}
|
||||
|
||||
qint64 AudioParams::time_to_bytes(const rational &time) const
|
||||
{
|
||||
return time_to_bytes(time.toDouble());
|
||||
}
|
||||
|
||||
qint64 AudioParams::time_to_bytes_per_channel(const double &time) const
|
||||
{
|
||||
Q_ASSERT(is_valid());
|
||||
|
||||
return qint64(time_to_samples(time)) * bytes_per_sample_per_channel();
|
||||
}
|
||||
|
||||
qint64 AudioParams::time_to_bytes_per_channel(const rational &time) const
|
||||
{
|
||||
return time_to_bytes_per_channel(time.toDouble());
|
||||
}
|
||||
|
||||
qint64 AudioParams::time_to_samples(const double &time) const
|
||||
{
|
||||
Q_ASSERT(is_valid());
|
||||
|
||||
// NOTE: Not sure if we should round or ceil, but I've gotten better results with ceil.
|
||||
// Specifically, we seem to occasionally get straggler ranges that never cache with round.
|
||||
return qCeil(double(sample_rate()) * time);
|
||||
}
|
||||
|
||||
qint64 AudioParams::time_to_samples(const rational &time) const
|
||||
{
|
||||
return time_to_samples(time.toDouble());
|
||||
}
|
||||
|
||||
qint64 AudioParams::samples_to_bytes(const qint64 &samples) const
|
||||
{
|
||||
Q_ASSERT(is_valid());
|
||||
|
||||
return samples_to_bytes_per_channel(samples) * channel_count();
|
||||
}
|
||||
|
||||
qint64 AudioParams::samples_to_bytes_per_channel(const qint64 &samples) const
|
||||
{
|
||||
Q_ASSERT(is_valid());
|
||||
|
||||
return samples * bytes_per_sample_per_channel();
|
||||
}
|
||||
|
||||
rational AudioParams::samples_to_time(const qint64 &samples) const
|
||||
{
|
||||
return sample_rate_as_time_base() * samples;
|
||||
}
|
||||
|
||||
qint64 AudioParams::bytes_to_samples(const qint64 &bytes) const
|
||||
{
|
||||
Q_ASSERT(is_valid());
|
||||
|
||||
return bytes / (channel_count() * bytes_per_sample_per_channel());
|
||||
}
|
||||
|
||||
rational AudioParams::bytes_to_time(const qint64 &bytes) const
|
||||
{
|
||||
Q_ASSERT(is_valid());
|
||||
|
||||
return samples_to_time(bytes_to_samples(bytes));
|
||||
}
|
||||
|
||||
rational AudioParams::bytes_per_channel_to_time(const qint64 &bytes) const
|
||||
{
|
||||
Q_ASSERT(is_valid());
|
||||
|
||||
return samples_to_time(bytes_to_samples(bytes * channel_count()));
|
||||
}
|
||||
|
||||
int AudioParams::channel_count() const
|
||||
{
|
||||
return channel_count_;
|
||||
}
|
||||
|
||||
int AudioParams::bytes_per_sample_per_channel() const
|
||||
{
|
||||
switch (format_) {
|
||||
case kFormatUnsigned8Packed:
|
||||
case kFormatUnsigned8Planar:
|
||||
return 1;
|
||||
case kFormatSigned16Packed:
|
||||
case kFormatSigned16Planar:
|
||||
return 2;
|
||||
case kFormatSigned32Packed:
|
||||
case kFormatSigned32Planar:
|
||||
case kFormatFloat32Packed:
|
||||
case kFormatFloat32Planar:
|
||||
return 4;
|
||||
case kFormatSigned64Packed:
|
||||
case kFormatSigned64Planar:
|
||||
case kFormatFloat64Packed:
|
||||
case kFormatFloat64Planar:
|
||||
return 8;
|
||||
case kFormatInvalid:
|
||||
case kFormatCount:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AudioParams::bits_per_sample() const
|
||||
{
|
||||
return bytes_per_sample_per_channel() * 8;
|
||||
}
|
||||
|
||||
bool AudioParams::is_valid() const
|
||||
{
|
||||
return (!time_base().isNull()
|
||||
&& channel_layout() > 0
|
||||
&& format_ > kFormatInvalid
|
||||
&& format_ < kFormatCount);
|
||||
}
|
||||
|
||||
void AudioParams::Load(QXmlStreamReader *reader)
|
||||
{
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("samplerate")) {
|
||||
set_sample_rate(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("channellayout")) {
|
||||
set_channel_layout(reader->readElementText().toULongLong());
|
||||
} else if (reader->name() == QStringLiteral("format")) {
|
||||
set_format(static_cast<AudioParams::Format>(reader->readElementText().toInt()));
|
||||
} else if (reader->name() == QStringLiteral("enabled")) {
|
||||
set_enabled(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("streamindex")) {
|
||||
set_stream_index(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("duration")) {
|
||||
set_duration(reader->readElementText().toLongLong());
|
||||
} else if (reader->name() == QStringLiteral("timebase")) {
|
||||
set_time_base(rational::fromString(reader->readElementText()));
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioParams::Save(QXmlStreamWriter *writer) const
|
||||
{
|
||||
writer->writeTextElement(QStringLiteral("samplerate"), QString::number(sample_rate_));
|
||||
writer->writeTextElement(QStringLiteral("channellayout"), QString::number(channel_layout_));
|
||||
writer->writeTextElement(QStringLiteral("format"), QString::number(format_));
|
||||
writer->writeTextElement(QStringLiteral("enabled"), QString::number(enabled_));
|
||||
writer->writeTextElement(QStringLiteral("streamindex"), QString::number(stream_index_));
|
||||
writer->writeTextElement(QStringLiteral("duration"), QString::number(duration_));
|
||||
writer->writeTextElement(QStringLiteral("timebase"), timebase_.toString());
|
||||
}
|
||||
|
||||
QString AudioParams::SampleRateToString(const int &sample_rate)
|
||||
{
|
||||
return QCoreApplication::translate("AudioParams", "%1 Hz").arg(sample_rate);
|
||||
}
|
||||
|
||||
QString AudioParams::ChannelLayoutToString(const uint64_t &layout)
|
||||
{
|
||||
switch (layout) {
|
||||
case AV_CH_LAYOUT_MONO:
|
||||
return QCoreApplication::translate("AudioParams", "Mono");
|
||||
case AV_CH_LAYOUT_STEREO:
|
||||
return QCoreApplication::translate("AudioParams", "Stereo");
|
||||
case AV_CH_LAYOUT_2_1:
|
||||
return QCoreApplication::translate("AudioParams", "2.1");
|
||||
case AV_CH_LAYOUT_5POINT1:
|
||||
return QCoreApplication::translate("AudioParams", "5.1");
|
||||
case AV_CH_LAYOUT_7POINT1:
|
||||
return QCoreApplication::translate("AudioParams", "7.1");
|
||||
default:
|
||||
return QCoreApplication::translate("AudioParams", "Unknown (0x%1)").arg(layout, 1, 16);
|
||||
}
|
||||
}
|
||||
|
||||
QString AudioParams::FormatToString(const Format &f)
|
||||
{
|
||||
switch (f) {
|
||||
case kFormatUnsigned8Packed:
|
||||
return QCoreApplication::translate("AudioParams", "Unsigned 8-bit (Packed)");
|
||||
case kFormatSigned16Packed:
|
||||
return QCoreApplication::translate("AudioParams", "Signed 16-bit (Packed)");
|
||||
case kFormatSigned32Packed:
|
||||
return QCoreApplication::translate("AudioParams", "Signed 32-bit (Packed)");
|
||||
case kFormatSigned64Packed:
|
||||
return QCoreApplication::translate("AudioParams", "Signed 64-bit (Packed)");
|
||||
case kFormatFloat32Packed:
|
||||
return QCoreApplication::translate("AudioParams", "Float 32-bit (Packed)");
|
||||
case kFormatFloat64Packed:
|
||||
return QCoreApplication::translate("AudioParams", "Float 64-bit (Packed)");
|
||||
case kFormatUnsigned8Planar:
|
||||
return QCoreApplication::translate("AudioParams", "Unsigned 8-bit (Planar)");
|
||||
case kFormatSigned16Planar:
|
||||
return QCoreApplication::translate("AudioParams", "Signed 16-bit (Planar)");
|
||||
case kFormatSigned32Planar:
|
||||
return QCoreApplication::translate("AudioParams", "Signed 32-bit (Planar)");
|
||||
case kFormatSigned64Planar:
|
||||
return QCoreApplication::translate("AudioParams", "Signed 64-bit (Planar)");
|
||||
case kFormatFloat32Planar:
|
||||
return QCoreApplication::translate("AudioParams", "Float 32-bit (Planar)");
|
||||
case kFormatFloat64Planar:
|
||||
return QCoreApplication::translate("AudioParams", "Float 64-bit (Planar)");
|
||||
|
||||
case kFormatInvalid:
|
||||
case kFormatCount:
|
||||
break;
|
||||
}
|
||||
|
||||
return QCoreApplication::translate("AudioParams", "Unknown (0x%1)").arg(f, 1, 16);
|
||||
}
|
||||
|
||||
AudioParams::Format AudioParams::GetPackedEquivalent(Format fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
|
||||
// For packed input, just return input
|
||||
case kFormatUnsigned8Packed:
|
||||
case kFormatSigned16Packed:
|
||||
case kFormatSigned32Packed:
|
||||
case kFormatSigned64Packed:
|
||||
case kFormatFloat32Packed:
|
||||
case kFormatFloat64Packed:
|
||||
return fmt;
|
||||
|
||||
// Convert to packed
|
||||
case kFormatUnsigned8Planar:
|
||||
return kFormatUnsigned8Packed;
|
||||
case kFormatSigned16Planar:
|
||||
return kFormatSigned16Packed;
|
||||
case kFormatSigned32Planar:
|
||||
return kFormatSigned32Packed;
|
||||
case kFormatSigned64Planar:
|
||||
return kFormatSigned64Packed;
|
||||
case kFormatFloat32Planar:
|
||||
return kFormatFloat32Packed;
|
||||
case kFormatFloat64Planar:
|
||||
return kFormatFloat64Packed;
|
||||
|
||||
case kFormatInvalid:
|
||||
case kFormatCount:
|
||||
break;
|
||||
}
|
||||
|
||||
return kFormatInvalid;
|
||||
}
|
||||
|
||||
AudioParams::Format AudioParams::GetPlanarEquivalent(Format fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
|
||||
// Convert to planar
|
||||
case kFormatUnsigned8Packed:
|
||||
return kFormatUnsigned8Planar;
|
||||
case kFormatSigned16Packed:
|
||||
return kFormatSigned16Planar;
|
||||
case kFormatSigned32Packed:
|
||||
return kFormatSigned32Planar;
|
||||
case kFormatSigned64Packed:
|
||||
return kFormatSigned64Planar;
|
||||
case kFormatFloat32Packed:
|
||||
return kFormatFloat32Planar;
|
||||
case kFormatFloat64Packed:
|
||||
return kFormatFloat64Planar;
|
||||
|
||||
// For planar input, just return input
|
||||
case kFormatUnsigned8Planar:
|
||||
case kFormatSigned16Planar:
|
||||
case kFormatSigned32Planar:
|
||||
case kFormatSigned64Planar:
|
||||
case kFormatFloat32Planar:
|
||||
case kFormatFloat64Planar:
|
||||
return fmt;
|
||||
|
||||
case kFormatInvalid:
|
||||
case kFormatCount:
|
||||
break;
|
||||
}
|
||||
|
||||
return kFormatInvalid;
|
||||
}
|
||||
|
||||
void AudioParams::calculate_channel_count()
|
||||
{
|
||||
channel_count_ = av_get_channel_layout_nb_channels(channel_layout());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef AUDIOPARAMS_H
|
||||
#define AUDIOPARAMS_H
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/channel_layout.h>
|
||||
}
|
||||
|
||||
#include <QtMath>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#include "common/rational.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class AudioParams {
|
||||
public:
|
||||
// Only append to this list (never insert) because indexes are used in serialized files
|
||||
enum Format {
|
||||
/// Invalid
|
||||
kFormatInvalid = -1,
|
||||
|
||||
/// 8-bit unsigned integer
|
||||
kFormatUnsigned8Planar,
|
||||
|
||||
/// 16-bit signed integer
|
||||
kFormatSigned16Planar,
|
||||
|
||||
/// 32-bit signed integer
|
||||
kFormatSigned32Planar,
|
||||
|
||||
/// 64-bit signed integer
|
||||
kFormatSigned64Planar,
|
||||
|
||||
/// 32-bit float
|
||||
kFormatFloat32Planar,
|
||||
|
||||
/// 64-bit float
|
||||
kFormatFloat64Planar,
|
||||
|
||||
/// 8-bit unsigned integer
|
||||
kFormatUnsigned8Packed,
|
||||
|
||||
/// 16-bit signed integer
|
||||
kFormatSigned16Packed,
|
||||
|
||||
/// 32-bit signed integer
|
||||
kFormatSigned32Packed,
|
||||
|
||||
/// 64-bit signed integer
|
||||
kFormatSigned64Packed,
|
||||
|
||||
/// 32-bit float
|
||||
kFormatFloat32Packed,
|
||||
|
||||
/// 64-bit float
|
||||
kFormatFloat64Packed,
|
||||
|
||||
/// Total format count
|
||||
kFormatCount,
|
||||
|
||||
kPlanarStart = kFormatUnsigned8Planar,
|
||||
kPackedStart = kFormatUnsigned8Packed,
|
||||
kPlanarEnd = kPackedStart,
|
||||
kPackedEnd = kFormatCount
|
||||
};
|
||||
|
||||
static const Format kInternalFormat;
|
||||
|
||||
AudioParams() :
|
||||
sample_rate_(0),
|
||||
channel_layout_(0),
|
||||
format_(kFormatInvalid)
|
||||
{
|
||||
set_default_footage_parameters();
|
||||
|
||||
// Cache channel count
|
||||
calculate_channel_count();
|
||||
}
|
||||
|
||||
AudioParams(const int& sample_rate, const uint64_t& channel_layout, const Format& format) :
|
||||
sample_rate_(sample_rate),
|
||||
channel_layout_(channel_layout),
|
||||
format_(format)
|
||||
{
|
||||
set_default_footage_parameters();
|
||||
timebase_ = sample_rate_as_time_base();
|
||||
|
||||
// Cache channel count
|
||||
calculate_channel_count();
|
||||
}
|
||||
|
||||
int sample_rate() const
|
||||
{
|
||||
return sample_rate_;
|
||||
}
|
||||
|
||||
void set_sample_rate(int sample_rate)
|
||||
{
|
||||
sample_rate_ = sample_rate;
|
||||
}
|
||||
|
||||
uint64_t channel_layout() const
|
||||
{
|
||||
return channel_layout_;
|
||||
}
|
||||
|
||||
void set_channel_layout(uint64_t channel_layout)
|
||||
{
|
||||
channel_layout_ = channel_layout;
|
||||
calculate_channel_count();
|
||||
}
|
||||
|
||||
rational time_base() const
|
||||
{
|
||||
return timebase_;
|
||||
}
|
||||
|
||||
void set_time_base(const rational& timebase)
|
||||
{
|
||||
timebase_ = timebase;
|
||||
}
|
||||
|
||||
rational sample_rate_as_time_base() const
|
||||
{
|
||||
return rational(1, sample_rate());
|
||||
}
|
||||
|
||||
Format format() const
|
||||
{
|
||||
return format_;
|
||||
}
|
||||
|
||||
void set_format(Format format)
|
||||
{
|
||||
format_ = format;
|
||||
}
|
||||
|
||||
bool enabled() const
|
||||
{
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
void set_enabled(bool e)
|
||||
{
|
||||
enabled_ = e;
|
||||
}
|
||||
|
||||
int stream_index() const
|
||||
{
|
||||
return stream_index_;
|
||||
}
|
||||
|
||||
void set_stream_index(int s)
|
||||
{
|
||||
stream_index_ = s;
|
||||
}
|
||||
|
||||
int64_t duration() const
|
||||
{
|
||||
return duration_;
|
||||
}
|
||||
|
||||
void set_duration(int64_t duration)
|
||||
{
|
||||
duration_ = duration;
|
||||
}
|
||||
|
||||
static bool FormatIsPacked(Format f)
|
||||
{
|
||||
return f >= kPackedStart && f < kPackedEnd;
|
||||
}
|
||||
|
||||
bool FormatIsPacked() const
|
||||
{
|
||||
return FormatIsPacked(format_);
|
||||
}
|
||||
|
||||
static bool FormatIsPlanar(Format f)
|
||||
{
|
||||
return f >= kPlanarStart && f < kPlanarEnd;
|
||||
}
|
||||
|
||||
bool FormatIsPlanar() const
|
||||
{
|
||||
return FormatIsPlanar(format_);
|
||||
}
|
||||
|
||||
qint64 time_to_bytes(const double& time) const;
|
||||
qint64 time_to_bytes(const rational& time) const;
|
||||
qint64 time_to_bytes_per_channel(const double& time) const;
|
||||
qint64 time_to_bytes_per_channel(const rational& time) const;
|
||||
qint64 time_to_samples(const double& time) const;
|
||||
qint64 time_to_samples(const rational& time) const;
|
||||
qint64 samples_to_bytes(const qint64& samples) const;
|
||||
qint64 samples_to_bytes_per_channel(const qint64& samples) const;
|
||||
rational samples_to_time(const qint64& samples) const;
|
||||
qint64 bytes_to_samples(const qint64 &bytes) const;
|
||||
rational bytes_to_time(const qint64 &bytes) const;
|
||||
rational bytes_per_channel_to_time(const qint64 &bytes) const;
|
||||
int channel_count() const;
|
||||
int bytes_per_sample_per_channel() const;
|
||||
int bits_per_sample() const;
|
||||
bool is_valid() const;
|
||||
|
||||
void Load(QXmlStreamReader* reader);
|
||||
|
||||
void Save(QXmlStreamWriter* writer) const;
|
||||
|
||||
bool operator==(const AudioParams& other) const;
|
||||
bool operator!=(const AudioParams& other) const;
|
||||
|
||||
static const QVector<uint64_t> kSupportedChannelLayouts;
|
||||
static const QVector<int> kSupportedSampleRates;
|
||||
|
||||
/**
|
||||
* @brief Convert integer sample rate to a user-friendly string
|
||||
*/
|
||||
static QString SampleRateToString(const int &sample_rate);
|
||||
|
||||
/**
|
||||
* @brief Convert channel layout to a user-friendly string
|
||||
*/
|
||||
static QString ChannelLayoutToString(const uint64_t &layout);
|
||||
|
||||
static QString FormatToString(const Format &f);
|
||||
|
||||
static AudioParams::Format GetPackedEquivalent(AudioParams::Format fmt);
|
||||
static AudioParams::Format GetPlanarEquivalent(AudioParams::Format fmt);
|
||||
|
||||
private:
|
||||
void set_default_footage_parameters()
|
||||
{
|
||||
enabled_ = true;
|
||||
stream_index_ = 0;
|
||||
duration_ = 0;
|
||||
}
|
||||
|
||||
void calculate_channel_count();
|
||||
|
||||
int sample_rate_;
|
||||
|
||||
uint64_t channel_layout_;
|
||||
|
||||
int channel_count_;
|
||||
|
||||
Format format_;
|
||||
|
||||
// Footage-specific
|
||||
int enabled_; // Switching this to int fixes GCC 11 stringop-overflow issue, I guess a byte-alignment issue?
|
||||
int stream_index_;
|
||||
int64_t duration_;
|
||||
rational timebase_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(olive::AudioParams)
|
||||
|
||||
#endif // AUDIOPARAMS_H
|
||||
@@ -68,28 +68,28 @@ void AudioPlaybackCache::WriteSilence(const TimeRange &range)
|
||||
|
||||
bool AudioPlaybackCache::WritePartOfSampleBuffer(const SampleBuffer &samples, const rational &write_start, const rational &buffer_start, const rational &length)
|
||||
{
|
||||
qint64 length_in_bytes = params_.time_to_bytes_per_channel(length);
|
||||
int64_t length_in_bytes = params_.time_to_bytes_per_channel(length);
|
||||
|
||||
qint64 start_cache_offset = params_.time_to_bytes_per_channel(write_start);
|
||||
qint64 end_cache_offset = start_cache_offset + length_in_bytes;
|
||||
int64_t start_cache_offset = params_.time_to_bytes_per_channel(write_start);
|
||||
int64_t end_cache_offset = start_cache_offset + length_in_bytes;
|
||||
|
||||
qint64 start_buffer_offset = params_.time_to_bytes_per_channel(buffer_start);
|
||||
qint64 end_buffer_offset = std::min(start_buffer_offset + length_in_bytes, params_.samples_to_bytes_per_channel(samples.sample_count()));
|
||||
int64_t start_buffer_offset = params_.time_to_bytes_per_channel(buffer_start);
|
||||
int64_t end_buffer_offset = std::min(start_buffer_offset + length_in_bytes, params_.samples_to_bytes_per_channel(samples.sample_count()));
|
||||
|
||||
qint64 current_cache_offset = start_cache_offset;
|
||||
qint64 current_buffer_offset = start_buffer_offset;
|
||||
int64_t current_cache_offset = start_cache_offset;
|
||||
int64_t current_buffer_offset = start_buffer_offset;
|
||||
|
||||
bool success = true;
|
||||
|
||||
while (current_cache_offset != end_cache_offset) {
|
||||
qint64 segment = current_cache_offset / kDefaultSegmentSizePerChannel;
|
||||
qint64 segment_start = segment * kDefaultSegmentSizePerChannel;
|
||||
qint64 segment_end = segment_start + kDefaultSegmentSizePerChannel;
|
||||
int64_t segment = current_cache_offset / kDefaultSegmentSizePerChannel;
|
||||
int64_t segment_start = segment * kDefaultSegmentSizePerChannel;
|
||||
int64_t segment_end = segment_start + kDefaultSegmentSizePerChannel;
|
||||
|
||||
qint64 offset_in_segment = current_cache_offset - segment_start;
|
||||
qint64 write_len = segment_end - offset_in_segment;
|
||||
qint64 max_buffer_len = end_buffer_offset - current_buffer_offset;
|
||||
qint64 zero_len = 0;
|
||||
int64_t offset_in_segment = current_cache_offset - segment_start;
|
||||
int64_t write_len = segment_end - offset_in_segment;
|
||||
int64_t max_buffer_len = end_buffer_offset - current_buffer_offset;
|
||||
int64_t zero_len = 0;
|
||||
|
||||
if (write_len > max_buffer_len) {
|
||||
zero_len = write_len - max_buffer_len;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user