renderer: move conform to task
Improved rendering system and user interface Fixes #1375
This commit is contained in:
@@ -19,21 +19,23 @@ add_subdirectory(oiio)
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
codec/decoder.h
|
||||
codec/conformmanager.cpp
|
||||
codec/conformmanager.h
|
||||
codec/decoder.cpp
|
||||
codec/encoder.h
|
||||
codec/decoder.h
|
||||
codec/encoder.cpp
|
||||
codec/exportcodec.h
|
||||
codec/encoder.h
|
||||
codec/exportcodec.cpp
|
||||
codec/exportformat.h
|
||||
codec/exportcodec.h
|
||||
codec/exportformat.cpp
|
||||
codec/frame.h
|
||||
codec/exportformat.h
|
||||
codec/frame.cpp
|
||||
codec/samplebuffer.h
|
||||
codec/frame.h
|
||||
codec/samplebuffer.cpp
|
||||
codec/waveinput.h
|
||||
codec/samplebuffer.h
|
||||
codec/waveinput.cpp
|
||||
codec/waveoutput.h
|
||||
codec/waveinput.h
|
||||
codec/waveoutput.cpp
|
||||
codec/waveoutput.h
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
+15
-67
@@ -30,18 +30,12 @@
|
||||
#include "common/ffmpegutils.h"
|
||||
#include "common/filefunctions.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "conformmanager.h"
|
||||
#include "node/project/project.h"
|
||||
#ifdef USE_OTIO
|
||||
#include "task/project/loadotio/loadotio.h"
|
||||
#endif
|
||||
#include "task/taskmanager.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
QMutex Decoder::currently_conforming_mutex_;
|
||||
QWaitCondition Decoder::currently_conforming_wait_cond_;
|
||||
QVector<Decoder::CurrentlyConforming> Decoder::currently_conforming_;
|
||||
|
||||
const rational Decoder::kAnyTimecode = RATIONAL_MIN;
|
||||
|
||||
Decoder::Decoder()
|
||||
@@ -112,7 +106,7 @@ FramePtr Decoder::RetrieveVideo(const rational &timecode, const RetrieveVideoPar
|
||||
return RetrieveVideoInternal(timecode, divider);
|
||||
}
|
||||
|
||||
SampleBufferPtr Decoder::RetrieveAudio(const TimeRange &range, const AudioParams ¶ms, const QString& cache_path, Footage::LoopMode loop_mode, const QAtomicInt *cancelled)
|
||||
Decoder::RetrieveAudioData Decoder::RetrieveAudio(const TimeRange &range, const AudioParams ¶ms, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode)
|
||||
{
|
||||
QMutexLocker locker(&mutex_);
|
||||
|
||||
@@ -120,58 +114,24 @@ SampleBufferPtr Decoder::RetrieveAudio(const TimeRange &range, const AudioParams
|
||||
|
||||
if (!stream_.IsValid()) {
|
||||
qCritical() << "Can't retrieve audio on a closed decoder";
|
||||
return nullptr;
|
||||
return {kInvalid, nullptr, nullptr};
|
||||
}
|
||||
|
||||
if (!SupportsAudio()) {
|
||||
qCritical() << "Decoder doesn't support audio";
|
||||
return nullptr;
|
||||
return {kInvalid, nullptr, nullptr};
|
||||
}
|
||||
|
||||
// Determine if we already have a conformed version
|
||||
QString conform_filename = GetConformedFilename(cache_path, params);
|
||||
CurrentlyConforming want_conform = {stream_, params};
|
||||
|
||||
currently_conforming_mutex_.lock();
|
||||
|
||||
// Wait for conform to complete
|
||||
while (currently_conforming_.contains(want_conform)) {
|
||||
currently_conforming_wait_cond_.wait(¤tly_conforming_mutex_);
|
||||
// Get conform state from ConformManager
|
||||
ConformManager::Conform conform = ConformManager::instance()->GetConformState(id(), cache_path, stream_, params, (mode == RenderMode::kOnline));
|
||||
if (conform.state == ConformManager::kConformGenerating) {
|
||||
return {kWaitingForConform, nullptr, conform.task};
|
||||
}
|
||||
|
||||
// See if we got the conform
|
||||
SampleBufferPtr buffer = RetrieveAudioFromConform(conform_filename, range, loop_mode);
|
||||
SampleBufferPtr out_buffer = RetrieveAudioFromConform(conform.filename, range, loop_mode);
|
||||
|
||||
if (!buffer) {
|
||||
// We'll need to conform this ourselves
|
||||
currently_conforming_.append(want_conform);
|
||||
currently_conforming_mutex_.unlock();
|
||||
|
||||
// We conform to a different filename until it's done to make it clear even across sessions
|
||||
// whether this conform is ready or not
|
||||
QString working_fn = conform_filename;
|
||||
working_fn.append(QStringLiteral(".working"));
|
||||
|
||||
if (ConformAudioInternal(working_fn, params, cancelled)) {
|
||||
// Move file to standard conform name, making it clear this conform is ready for use
|
||||
QFile::remove(conform_filename);
|
||||
QFile::rename(working_fn, conform_filename);
|
||||
|
||||
// Return audio as planned
|
||||
buffer = RetrieveAudioFromConform(conform_filename, range, loop_mode);
|
||||
} else {
|
||||
// Failed
|
||||
qCritical() << "Failed to conform audio";
|
||||
}
|
||||
|
||||
currently_conforming_mutex_.lock();
|
||||
currently_conforming_.removeOne(want_conform);
|
||||
currently_conforming_wait_cond_.wakeAll();
|
||||
}
|
||||
|
||||
currently_conforming_mutex_.unlock();
|
||||
|
||||
return buffer;
|
||||
return {kOK, out_buffer, nullptr};
|
||||
}
|
||||
|
||||
qint64 Decoder::GetLastAccessedTime()
|
||||
@@ -194,6 +154,11 @@ void Decoder::Close()
|
||||
}
|
||||
}
|
||||
|
||||
bool Decoder::ConformAudio(const QString &output_filename, const AudioParams ¶ms, const QAtomicInt *cancelled)
|
||||
{
|
||||
return ConformAudioInternal(output_filename, params, cancelled);
|
||||
}
|
||||
|
||||
/*
|
||||
* DECODER STATIC PUBLIC MEMBERS
|
||||
*/
|
||||
@@ -228,23 +193,6 @@ DecoderPtr Decoder::CreateFromID(const QString &id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString Decoder::GetConformedFilename(const QString& cache_path, const AudioParams ¶ms)
|
||||
{
|
||||
QString index_fn = QStringLiteral("%1.%2:%3").arg(FileFunctions::GetUniqueFileIdentifier(stream_.filename()),
|
||||
QString::number(stream_.stream()));
|
||||
|
||||
index_fn = QDir(cache_path).filePath(index_fn);
|
||||
|
||||
index_fn.append('.');
|
||||
index_fn.append(QString::number(params.sample_rate()));
|
||||
index_fn.append('.');
|
||||
index_fn.append(QString::number(params.format()));
|
||||
index_fn.append('.');
|
||||
index_fn.append(QString::number(params.channel_layout()));
|
||||
|
||||
return index_fn;
|
||||
}
|
||||
|
||||
int64_t Decoder::GetTimeInTimebaseUnits(const rational &time, const rational &timebase, int64_t start_time)
|
||||
{
|
||||
return Timecode::time_to_timestamp(time, timebase) + start_time;
|
||||
|
||||
+19
-20
@@ -37,6 +37,7 @@ extern "C" {
|
||||
#include "common/rational.h"
|
||||
#include "node/project/footage/footage.h"
|
||||
#include "node/project/footage/footagedescription.h"
|
||||
#include "task/task.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -184,6 +185,18 @@ public:
|
||||
*/
|
||||
FramePtr RetrieveVideo(const rational& timecode, const RetrieveVideoParams& divider);
|
||||
|
||||
enum RetrieveAudioStatus {
|
||||
kInvalid = -1,
|
||||
kOK,
|
||||
kWaitingForConform
|
||||
};
|
||||
|
||||
struct RetrieveAudioData {
|
||||
RetrieveAudioStatus status;
|
||||
SampleBufferPtr samples;
|
||||
Task *task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Retrieve audio data from footage
|
||||
*
|
||||
@@ -192,7 +205,7 @@ public:
|
||||
*
|
||||
* This function is thread safe and can only run while the decoder is open. \see Open()
|
||||
*/
|
||||
SampleBufferPtr RetrieveAudio(const TimeRange& range, const AudioParams& params, const QString &cache_path, Footage::LoopMode loop_mode, const QAtomicInt *cancelled);
|
||||
RetrieveAudioData RetrieveAudio(const TimeRange& range, const AudioParams& params, const QString &cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode);
|
||||
|
||||
/**
|
||||
* @brief Determine the last time this decoder instance was used in any way
|
||||
@@ -219,6 +232,11 @@ public:
|
||||
*/
|
||||
void Close();
|
||||
|
||||
/**
|
||||
* @brief Conform audio stream
|
||||
*/
|
||||
bool ConformAudio(const QString &output_filename, const AudioParams ¶ms, const QAtomicInt *cancelled = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Create a Decoder instance using a Decoder ID
|
||||
*
|
||||
@@ -271,21 +289,6 @@ protected:
|
||||
|
||||
void SignalProcessingProgress(int64_t ts, int64_t duration);
|
||||
|
||||
/**
|
||||
* @brief Get the destination filename of an audio stream conformed to a set of parameters
|
||||
*/
|
||||
QString GetConformedFilename(const QString &cache_path, const AudioParams ¶ms);
|
||||
|
||||
struct CurrentlyConforming {
|
||||
CodecStream stream;
|
||||
AudioParams params;
|
||||
|
||||
bool operator==(const CurrentlyConforming& rhs) const
|
||||
{
|
||||
return this->stream == rhs.stream && this->params == rhs.params;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return currently open stream
|
||||
*
|
||||
@@ -298,10 +301,6 @@ protected:
|
||||
|
||||
static int64_t GetTimeInTimebaseUnits(const rational& time, const rational& timebase, int64_t start_time);
|
||||
|
||||
static QMutex currently_conforming_mutex_;
|
||||
static QWaitCondition currently_conforming_wait_cond_;
|
||||
static QVector<CurrentlyConforming> currently_conforming_;
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief While indexing, this signal will provide progress as a percentage (0-100 inclusive) if
|
||||
|
||||
Reference in New Issue
Block a user