From a675e0ccbb5ba225a193185bb2cf109faee2e08d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 14 May 2021 12:22:30 +1000 Subject: [PATCH] conformmanager: actually commit new files --- app/codec/conformmanager.cpp | 105 +++++++++++++++++++++++++++++++++++ app/codec/conformmanager.h | 86 ++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 app/codec/conformmanager.cpp create mode 100644 app/codec/conformmanager.h diff --git a/app/codec/conformmanager.cpp b/app/codec/conformmanager.cpp new file mode 100644 index 000000000..38b5874a5 --- /dev/null +++ b/app/codec/conformmanager.cpp @@ -0,0 +1,105 @@ +#include "conformmanager.h" + +#include + +#include "task/taskmanager.h" + +namespace olive { + +ConformManager *ConformManager::instance_ = nullptr; + +ConformManager::Conform ConformManager::GetConformState(const QString &decoder_id, const QString &cache_path, const Decoder::CodecStream &stream, const AudioParams ¶ms, bool wait) +{ + // Mutex because we'll need to check the status of a conform task + QMutexLocker locker(&mutex_); + + // Return existing conform if exists + QString filename = GetConformedFilename(cache_path, stream, params); + if (QFileInfo::exists(filename)) { + return {kConformExists, filename, nullptr}; + } + + ConformTask *conforming_task = nullptr; + + foreach (const ConformData &data, conforming_) { + if (data.stream == stream && data.params == params) { + // Already creating conform in a task + conforming_task = data.task; + break; + } + } + + if (!conforming_task) { + // Not conforming yet, create a task to do so + + // 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 = filename; + working_fn.append(QStringLiteral(".working")); + + conforming_task = new ConformTask(decoder_id, stream, params, working_fn); + connect(conforming_task, &ConformTask::Finished, this, &ConformManager::ConformTaskFinished); + conforming_task->moveToThread(TaskManager::instance()->thread()); + QMetaObject::invokeMethod(TaskManager::instance(), "AddTask", Qt::QueuedConnection, Q_ARG(Task *, conforming_task)); + + conforming_.append({stream, params, conforming_task, working_fn, filename}); + } + + if (wait) { + do { + conform_done_condition_.wait(&mutex_); + } while (!QFileInfo::exists(filename)); + return {kConformExists, filename, nullptr}; + } + + return {kConformGenerating, QString(), conforming_task}; +} + +QString ConformManager::GetConformedFilename(const QString &cache_path, const Decoder::CodecStream &stream, 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; +} + +void ConformManager::ConformTaskFinished(Task *task, bool succeeded) +{ + QMutexLocker locker(&mutex_); + + ConformData data; + + // Remove conform data from list + for (int i=0; i +#include + +#include "decoder.h" +#include "task/conform/conform.h" + +namespace olive { + +class ConformManager : public QObject +{ + Q_OBJECT +public: + static void CreateInstance() + { + if (!instance_) { + instance_ = new ConformManager(); + } + } + + static void DestroyInstance() + { + delete instance_; + instance_ = nullptr; + } + + static ConformManager *instance() + { + return instance_; + } + + enum ConformState { + kConformExists, + kConformGenerating + }; + + struct Conform { + ConformState state; + QString filename; + ConformTask *task; + }; + + /** + * @brief Get conform state, and start conforming if no conform exists + * + * Thread-safe. + */ + Conform GetConformState(const QString &decoder_id, const QString &cache_path, const Decoder::CodecStream &stream, const AudioParams ¶ms, bool wait); + +signals: + void ConformReady(); + +private: + ConformManager() = default; + + static ConformManager *instance_; + + QMutex mutex_; + + QWaitCondition conform_done_condition_; + + struct ConformData { + Decoder::CodecStream stream; + AudioParams params; + ConformTask *task; + QString working_filename; + QString finished_filename; + }; + + QVector conforming_; + + /** + * @brief Get the destination filename of an audio stream conformed to a set of parameters + */ + static QString GetConformedFilename(const QString &cache_path, const Decoder::CodecStream &stream, const AudioParams ¶ms); + +private slots: + void ConformTaskFinished(Task *task, bool succeeded); + +}; + +} + +#endif // CONFORMMANAGER_H