diff --git a/gui/win_main.ui b/gui/win_main.ui index bd1dabf..e26ab73 100644 --- a/gui/win_main.ui +++ b/gui/win_main.ui @@ -11,7 +11,7 @@ - Simple x264 Launcher + Simple x264/x265 Launcher diff --git a/src/model_jobList.cpp b/src/model_jobList.cpp index 781ac51..f265f70 100644 --- a/src/model_jobList.cpp +++ b/src/model_jobList.cpp @@ -28,6 +28,14 @@ #include #include +#include + +static const char *KEY_ENTRY_COUNT = "entry_count"; +static const char *KEY_SOURCE_FILE = "source_file"; +static const char *KEY_OUTPUT_FILE = "output_file"; +static const char *KEY_ENC_OPTIONS = "enc_options"; + +static const char *JOB_TEMPLATE = "job_%08x"; JobListModel::JobListModel(PreferencesModel *preferences) { @@ -233,19 +241,29 @@ QModelIndex JobListModel::insertJob(EncodeThread *thread) QString config = "N/A"; + switch(thread->options()->rcMode()) + { + case OptionsModel::EncType_X264: + config = QString("x264"); + break; + case OptionsModel::EncType_X265: + config = QString("x265"); + break; + } + switch(thread->options()->rcMode()) { case OptionsModel::RCMode_CRF: - config = QString("CRF@%1").arg(QString::number(thread->options()->quantizer())); + config = QString("%1 CRF@%2") .arg(config, QString::number(thread->options()->quantizer())); break; case OptionsModel::RCMode_CQ: - config = QString("CQ@%1").arg(QString::number(qRound(thread->options()->quantizer()))); + config = QString("%1 CQ@%2") .arg(config, QString::number(qRound(thread->options()->quantizer()))); break; case OptionsModel::RCMode_2Pass: - config = QString("2Pass@%1").arg(QString::number(thread->options()->bitrate())); + config = QString("%1 2Pass@%2").arg(config, QString::number(thread->options()->bitrate())); break; case OptionsModel::RCMode_ABR: - config = QString("ABR@%1").arg(QString::number(thread->options()->bitrate())); + config = QString("%1 ABR@%2") .arg(config, QString::number(thread->options()->bitrate())); break; } @@ -525,3 +543,89 @@ void JobListModel::updateDetails(const QUuid &jobId, const QString &details) emit dataChanged(createIndex(index, 3), createIndex(index, 3)); } } + +size_t JobListModel::saveQueuedJobs(void) +{ + const QString appDir = x264_data_path(); + QSettings settings(QString("%1/queue.ini").arg(appDir), QSettings::IniFormat); + + settings.clear(); + settings.setValue(KEY_ENTRY_COUNT, 0); + size_t jobCounter = 0; + + for(QList::ConstIterator iter = m_jobs.constBegin(); iter != m_jobs.constEnd(); iter++) + { + if(m_status.value(*iter) == JobStatus_Enqueued) + { + if(const EncodeThread *thread = m_threads.value(*iter)) + { + settings.beginGroup(QString().sprintf(JOB_TEMPLATE, jobCounter++)); + settings.setValue(KEY_SOURCE_FILE, thread->sourceFileName()); + settings.setValue(KEY_OUTPUT_FILE, thread->outputFileName()); + + settings.beginGroup(KEY_ENC_OPTIONS); + OptionsModel::saveOptions(thread->options(), settings); + + settings.endGroup(); + settings.endGroup(); + + settings.setValue(KEY_ENTRY_COUNT, jobCounter); + } + } + } + + settings.sync(); + return jobCounter; +} + +size_t JobListModel::loadQueuedJobs(const SysinfoModel *sysinfo) +{ + const QString appDir = x264_data_path(); + QSettings settings(QString("%1/queue.ini").arg(appDir), QSettings::IniFormat); + + bool ok = false; + const size_t jobCounter = settings.value(KEY_ENTRY_COUNT, 0).toUInt(&ok); + + if((!ok) || (jobCounter < 1)) + { + return 0; + } + + size_t jobsCreated = 0; + + for(size_t i = 0; i < jobCounter; i++) + { + settings.beginGroup(QString().sprintf(JOB_TEMPLATE, i)); + const QString sourceFileName = settings.value(KEY_SOURCE_FILE, QString()).toString().trimmed(); + const QString outputFileName = settings.value(KEY_OUTPUT_FILE, QString()).toString().trimmed(); + + if(sourceFileName.isEmpty() || outputFileName.isEmpty()) + { + settings.endGroup(); + continue; + } + + settings.beginGroup(KEY_ENC_OPTIONS); + OptionsModel options(sysinfo); + const bool okay = OptionsModel::loadOptions(&options, settings); + + settings.endGroup(); + settings.endGroup(); + + if(okay) + { + EncodeThread *thread = new EncodeThread(sourceFileName, outputFileName, &options, sysinfo, m_preferences); + insertJob(thread); + jobsCreated++; + } + } + + return jobsCreated; +} + +void JobListModel::clearQueuedJobs(void) +{ + const QString appDir = x264_data_path(); + QSettings settings(QString("%1/queue.ini").arg(appDir), QSettings::IniFormat); + settings.clear(); +} diff --git a/src/model_jobList.h b/src/model_jobList.h index a941a7e..648b9f3 100644 --- a/src/model_jobList.h +++ b/src/model_jobList.h @@ -60,6 +60,10 @@ public: const OptionsModel *getJobOptions(const QModelIndex &index); QModelIndex getJobIndexById(const QUuid &id); + size_t saveQueuedJobs(void); + size_t loadQueuedJobs(const SysinfoModel *sysinfo); + void clearQueuedJobs(void); + protected: QList m_jobs; QMap m_name; diff --git a/src/model_options.cpp b/src/model_options.cpp index 082571c..76a3628 100644 --- a/src/model_options.cpp +++ b/src/model_options.cpp @@ -124,7 +124,7 @@ bool OptionsModel::equals(const OptionsModel *model) return equal; } -bool OptionsModel::saveTemplate(OptionsModel *model, const QString &name) +bool OptionsModel::saveTemplate(const OptionsModel *model, const QString &name) { const QString templateName = name.simplified(); const QString appDir = x264_data_path(); @@ -137,22 +137,12 @@ bool OptionsModel::saveTemplate(OptionsModel *model, const QString &name) QSettings settings(QString("%1/templates.ini").arg(appDir), QSettings::IniFormat); settings.beginGroup(templateName); - settings.setValue(KEY_ENCODER_TYPE, model->m_encoderType); - settings.setValue(KEY_ENCODER_ARCH, model->m_encoderArch); - settings.setValue(KEY_ENCODER_VARIANT, model->m_encoderVariant); - settings.setValue(KEY_RATECTRL_MODE, model->m_rcMode); - settings.setValue(KEY_TARGET_BITRATE, model->m_bitrate); - settings.setValue(KEY_TARGET_QUANT, model->m_quantizer); - settings.setValue(KEY_PRESET_NAME, model->m_preset); - settings.setValue(KEY_TUNING_NAME, model->m_tune); - settings.setValue(KEY_PROFILE_NAME, model->m_profile); - settings.setValue(KEY_CUSTOM_ENCODER, model->m_custom_encoder); - settings.setValue(KEY_CUSTOM_AVS2YUV, model->m_custom_avs2yuv); - + const bool okay = saveOptions(model, settings); + settings.endGroup(); settings.sync(); - return true; + return okay; } bool OptionsModel::loadTemplate(OptionsModel *model, const QString &name) @@ -167,57 +157,10 @@ bool OptionsModel::loadTemplate(OptionsModel *model, const QString &name) QSettings settings(QString("%1/templates.ini").arg(appDir), QSettings::IniFormat); settings.beginGroup(name); - //For backward-compatibility - static const char *legacyKey[] = { "custom_params", "custom_params_x264", NULL }; - for(int i = 0; legacyKey[i]; i++) - { - if(settings.contains(legacyKey[i])) - { - settings.setValue(KEY_CUSTOM_ENCODER, settings.value(legacyKey[i])); - settings.remove(legacyKey[i]); - settings.sync(); - } - } - if(settings.value(KEY_PROFILE_NAME).toString().compare("auto", Qt::CaseInsensitive) == 0) - { - settings.setValue(KEY_PROFILE_NAME, QString::fromLatin1(OptionsModel::PROFILE_UNRESTRICTED)); - } - if(settings.value(KEY_TUNING_NAME).toString().compare("none", Qt::CaseInsensitive) == 0) - { - settings.setValue(KEY_TUNING_NAME, QString::fromLatin1(OptionsModel::TUNING_UNSPECIFIED)); - } - - bool complete = true; - - if(!settings.contains(KEY_ENCODER_TYPE)) complete = false; - if(!settings.contains(KEY_ENCODER_ARCH)) complete = false; - if(!settings.contains(KEY_ENCODER_VARIANT)) complete = false; - if(!settings.contains(KEY_RATECTRL_MODE)) complete = false; - if(!settings.contains(KEY_TARGET_BITRATE)) complete = false; - if(!settings.contains(KEY_TARGET_QUANT)) complete = false; - if(!settings.contains(KEY_PRESET_NAME)) complete = false; - if(!settings.contains(KEY_TUNING_NAME)) complete = false; - if(!settings.contains(KEY_PROFILE_NAME)) complete = false; - if(!settings.contains(KEY_CUSTOM_ENCODER)) complete = false; - if(!settings.contains(KEY_CUSTOM_AVS2YUV)) complete = false; - - if(complete) - { - model->setEncType (static_cast (settings.value(KEY_ENCODER_TYPE, model->m_encoderType) .toInt())); - model->setEncArch (static_cast (settings.value(KEY_ENCODER_ARCH, model->m_encoderArch) .toInt())); - model->setEncVariant (static_cast(settings.value(KEY_ENCODER_VARIANT, model->m_encoderVariant).toInt())); - model->setRCMode (static_cast (settings.value(KEY_RATECTRL_MODE, model->m_rcMode) .toInt())); - model->setBitrate (settings.value(KEY_TARGET_BITRATE, model->m_bitrate).toUInt() ); - model->setQuantizer (settings.value(KEY_TARGET_QUANT, model->m_quantizer).toDouble() ); - model->setPreset (settings.value(KEY_PRESET_NAME, model->m_preset).toString() ); - model->setTune (settings.value(KEY_TUNING_NAME, model->m_tune).toString() ); - model->setProfile (settings.value(KEY_PROFILE_NAME, model->m_profile).toString() ); - model->setCustomEncParams(settings.value(KEY_CUSTOM_ENCODER, model->m_custom_encoder).toString()); - model->setCustomAvs2YUV (settings.value(KEY_CUSTOM_AVS2YUV, model->m_custom_avs2yuv).toString()); - } + const bool okay = loadOptions(model, settings); settings.endGroup(); - return complete; + return okay; } QMap OptionsModel::loadAllTemplates(const SysinfoModel *sysinfo) @@ -266,3 +209,73 @@ bool OptionsModel::deleteTemplate(const QString &name) return false; } + +bool OptionsModel::saveOptions(const OptionsModel *model, QSettings &settingsFile) +{ + settingsFile.setValue(KEY_ENCODER_TYPE, model->m_encoderType); + settingsFile.setValue(KEY_ENCODER_ARCH, model->m_encoderArch); + settingsFile.setValue(KEY_ENCODER_VARIANT, model->m_encoderVariant); + settingsFile.setValue(KEY_RATECTRL_MODE, model->m_rcMode); + settingsFile.setValue(KEY_TARGET_BITRATE, model->m_bitrate); + settingsFile.setValue(KEY_TARGET_QUANT, model->m_quantizer); + settingsFile.setValue(KEY_PRESET_NAME, model->m_preset); + settingsFile.setValue(KEY_TUNING_NAME, model->m_tune); + settingsFile.setValue(KEY_PROFILE_NAME, model->m_profile); + settingsFile.setValue(KEY_CUSTOM_ENCODER, model->m_custom_encoder); + settingsFile.setValue(KEY_CUSTOM_AVS2YUV, model->m_custom_avs2yuv); + + return true; +} + +bool OptionsModel::loadOptions(OptionsModel *model, QSettings &settingsFile) +{ + //For backward-compatibility + static const char *legacyKey[] = { "custom_params", "custom_params_x264", NULL }; + for(int i = 0; legacyKey[i]; i++) + { + if(settingsFile.contains(legacyKey[i])) + { + settingsFile.setValue(KEY_CUSTOM_ENCODER, settingsFile.value(legacyKey[i])); + settingsFile.remove(legacyKey[i]); + } + } + if(settingsFile.value(KEY_PROFILE_NAME).toString().compare("auto", Qt::CaseInsensitive) == 0) + { + settingsFile.setValue(KEY_PROFILE_NAME, QString::fromLatin1(OptionsModel::PROFILE_UNRESTRICTED)); + } + if(settingsFile.value(KEY_TUNING_NAME).toString().compare("none", Qt::CaseInsensitive) == 0) + { + settingsFile.setValue(KEY_TUNING_NAME, QString::fromLatin1(OptionsModel::TUNING_UNSPECIFIED)); + } + + bool complete = true; + + if(!settingsFile.contains(KEY_ENCODER_TYPE)) complete = false; + if(!settingsFile.contains(KEY_ENCODER_ARCH)) complete = false; + if(!settingsFile.contains(KEY_ENCODER_VARIANT)) complete = false; + if(!settingsFile.contains(KEY_RATECTRL_MODE)) complete = false; + if(!settingsFile.contains(KEY_TARGET_BITRATE)) complete = false; + if(!settingsFile.contains(KEY_TARGET_QUANT)) complete = false; + if(!settingsFile.contains(KEY_PRESET_NAME)) complete = false; + if(!settingsFile.contains(KEY_TUNING_NAME)) complete = false; + if(!settingsFile.contains(KEY_PROFILE_NAME)) complete = false; + if(!settingsFile.contains(KEY_CUSTOM_ENCODER)) complete = false; + if(!settingsFile.contains(KEY_CUSTOM_AVS2YUV)) complete = false; + + if(complete) + { + model->setEncType (static_cast (settingsFile.value(KEY_ENCODER_TYPE, model->m_encoderType) .toInt())); + model->setEncArch (static_cast (settingsFile.value(KEY_ENCODER_ARCH, model->m_encoderArch) .toInt())); + model->setEncVariant (static_cast(settingsFile.value(KEY_ENCODER_VARIANT, model->m_encoderVariant).toInt())); + model->setRCMode (static_cast (settingsFile.value(KEY_RATECTRL_MODE, model->m_rcMode) .toInt())); + model->setBitrate (settingsFile.value(KEY_TARGET_BITRATE, model->m_bitrate) .toUInt() ); + model->setQuantizer (settingsFile.value(KEY_TARGET_QUANT, model->m_quantizer) .toDouble()); + model->setPreset (settingsFile.value(KEY_PRESET_NAME, model->m_preset) .toString()); + model->setTune (settingsFile.value(KEY_TUNING_NAME, model->m_tune) .toString()); + model->setProfile (settingsFile.value(KEY_PROFILE_NAME, model->m_profile) .toString()); + model->setCustomEncParams(settingsFile.value(KEY_CUSTOM_ENCODER, model->m_custom_encoder).toString()); + model->setCustomAvs2YUV (settingsFile.value(KEY_CUSTOM_AVS2YUV, model->m_custom_avs2yuv).toString()); + } + + return complete; +} diff --git a/src/model_options.h b/src/model_options.h index 72cee6e..95d94de 100644 --- a/src/model_options.h +++ b/src/model_options.h @@ -26,6 +26,7 @@ #include class SysinfoModel; +class QSettings; class OptionsModel { @@ -94,11 +95,13 @@ public: //Static functions static QString rcMode2String(RCMode mode); - static bool saveTemplate(OptionsModel *model, const QString &name); + static bool saveTemplate(const OptionsModel *model, const QString &name); static bool loadTemplate(OptionsModel *model, const QString &name); static QMap loadAllTemplates(const SysinfoModel *sysinfo); static bool templateExists(const QString &name); static bool deleteTemplate(const QString &name); + static bool saveOptions(const OptionsModel *model, QSettings &settingsFile); + static bool loadOptions(OptionsModel *model, QSettings &settingsFile); protected: EncType m_encoderType; diff --git a/src/thread_encode.h b/src/thread_encode.h index bfbccae..673c845 100644 --- a/src/thread_encode.h +++ b/src/thread_encode.h @@ -46,9 +46,9 @@ public: ~EncodeThread(void); QUuid getId(void) { return this->m_jobId; }; - const QString &sourceFileName(void) { return this->m_sourceFileName; } - const QString &outputFileName(void) { return this->m_outputFileName; } - const OptionsModel *options(void) { return m_options; } + const QString &sourceFileName(void) const { return this->m_sourceFileName; } + const QString &outputFileName(void) const { return this->m_outputFileName; } + const OptionsModel *options(void) const { return m_options; } void pauseJob(void) { diff --git a/src/version.h b/src/version.h index aab170b..86f6e3c 100644 --- a/src/version.h +++ b/src/version.h @@ -25,8 +25,8 @@ #define VER_X264_MAJOR 2 #define VER_X264_MINOR 3 -#define VER_X264_PATCH 6 -#define VER_X264_BUILD 826 +#define VER_X264_PATCH 7 +#define VER_X264_BUILD 829 #define VER_X264_PORTABLE_EDITION (0) diff --git a/src/win_main.cpp b/src/win_main.cpp index 4a767f8..ac25891 100644 --- a/src/win_main.cpp +++ b/src/win_main.cpp @@ -970,7 +970,7 @@ void MainWindow::init(void) //--------------------------------------- //Set Window title - setWindowTitle(QString("%1 (%2)").arg(tr("Simple %1 Launcher").arg(m_sysinfo->has256Support() ? "x264/x265" : "x264"), m_sysinfo->hasX64Support() ? "64-Bit" : "32-Bit")); + setWindowTitle(QString("%1 (%2)").arg(windowTitle(), m_sysinfo->hasX64Support() ? "64-Bit" : "32-Bit")); //Enable drag&drop support for this window, required for Qt v4.8.4+ setAcceptDrops(true); @@ -991,6 +991,12 @@ void MainWindow::init(void) } } } + + //Load queued jobs + if(m_jobList->loadQueuedJobs(m_sysinfo) > 0) + { + m_label->setVisible(m_jobList->rowCount(QModelIndex()) == 0); + } } /* @@ -1159,7 +1165,6 @@ void MainWindow::showEvent(QShowEvent *e) if(m_status == STATUS_PRE_INIT) { - setWindowTitle(tr("%1 - Starting...").arg(windowTitle())); QTimer::singleShot(0, this, SLOT(init())); } } @@ -1169,6 +1174,8 @@ void MainWindow::showEvent(QShowEvent *e) */ void MainWindow::closeEvent(QCloseEvent *e) { + bool bJobsHaveBeenSaved = false; + if((m_status != STATUS_IDLE) && (m_status != STATUS_EXITTING)) { e->ignore(); @@ -1176,6 +1183,7 @@ void MainWindow::closeEvent(QCloseEvent *e) return; } + //Make sure we have no running jobs left! if(m_status != STATUS_EXITTING) { if(countRunningJobs() > 0) @@ -1186,30 +1194,50 @@ void MainWindow::closeEvent(QCloseEvent *e) m_status = STATUS_IDLE; return; } - + + //Save pending jobs for next time, if desired by user if(countPendingJobs() > 0) { m_status = STATUS_BLOCKED; - int ret = QMessageBox::question(this, tr("Jobs Are Pending"), tr("Do you really want to quit and discard the pending jobs?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - if(ret != QMessageBox::Yes) + int ret = QMessageBox::question(this, tr("Jobs Are Pending"), tr("You still have pending jobs. How do you want to proceed?"), tr("Save Pending Jobs"), tr("Discard")); + if(ret == 0) { - e->ignore(); - m_status = STATUS_IDLE; - return; + if(m_jobList->saveQueuedJobs() > 0) + { + bJobsHaveBeenSaved = true; + } + } + else + { + if(QMessageBox::warning(this, tr("Jobs Are Pending"), tr("Do you really want to discard all pending jobs?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) + { + e->ignore(); + m_status = STATUS_IDLE; + return; + } } } } + + //Clear "old" pending jobs for next startup (only if we have not saved "new" jobs already!) + if(!bJobsHaveBeenSaved) + { + m_jobList->clearQueuedJobs(); + } + //Delete remaining jobs while(m_jobList->rowCount(QModelIndex()) > 0) { - qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + if((m_jobList->rowCount(QModelIndex()) % 10) == 0) + { + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + } if(!m_jobList->deleteJob(m_jobList->index(0, 0, QModelIndex()))) { e->ignore(); m_status = STATUS_BLOCKED; - QMessageBox::warning(this, tr("Failed To Exit"), tr("Sorry, at least one job could not be deleted!")); + QMessageBox::warning(this, tr("Failed To Exit"), tr("Warning: At least one job could not be deleted!")); m_status = STATUS_IDLE; - return; } }