diff --git a/src/program/Config.cpp b/src/program/Config.cpp index 705b15d0..a1a71fbd 100644 --- a/src/program/Config.cpp +++ b/src/program/Config.cpp @@ -78,6 +78,7 @@ void Config::save(const std::string& gamepath) { settings.setValue("autosave_frames", autosave_frames); settings.setValue("autosave_count", autosave_count); settings.setValue("auto_restart", auto_restart); + settings.setValue("merge_dump_segments", merge_dump_segments); settings.beginGroup("keymapping"); @@ -195,6 +196,7 @@ void Config::load(const std::string& gamepath) { autosave_frames = settings.value("autosave_frames", autosave_frames).toInt(); autosave_count = settings.value("autosave_count", autosave_count).toInt(); auto_restart = settings.value("auto_restart", auto_restart).toBool(); + merge_dump_segments = settings.value("merge_dump_segments", merge_dump_segments).toBool(); /* Load key mapping */ diff --git a/src/program/Config.h b/src/program/Config.h index fdd30ca9..cf9506a9 100644 --- a/src/program/Config.h +++ b/src/program/Config.h @@ -63,6 +63,9 @@ class Config { /* Were we started up with the -d option? */ bool dumping; + + /* Are we supposed to merge the segments after dumping? */ + bool merge_dump_segments = false; /* Path of the libraries used by the game */ std::string libdir; diff --git a/src/program/GameLoop.cpp b/src/program/GameLoop.cpp index 8ca78823..0cffbfeb 100644 --- a/src/program/GameLoop.cpp +++ b/src/program/GameLoop.cpp @@ -24,6 +24,7 @@ #include "GameLoop.h" #include "utils.h" #include "AutoSave.h" +#include "MergeHelperScript.h" #include "../shared/sockethelpers.h" #include "../shared/SharedConfig.h" @@ -43,6 +44,7 @@ #include // stat #include // waitpid #include +#include //system() #include #ifndef HAVE_PERSONALITY @@ -1108,6 +1110,8 @@ bool GameLoop::processEvent(uint8_t type, struct HotKey &hk) * allows to start a new encode on the same frame */ sendMessage(MSGN_STOP_ENCODE); + if (context->config.merge_dump_segments) + mergeSegments(); } emit sharedConfigChanged(); return false; @@ -1421,7 +1425,10 @@ void GameLoop::loopExit() emit statusChanged(); return; - } + } + /* If we're not restarting, then check if we need to merge the dumps */ + else if (context->config.sc.av_dumping && context->config.merge_dump_segments) + mergeSegments(); if (movie.modifiedSinceLastSave) { @@ -1451,3 +1458,14 @@ void GameLoop::loopExit() context->status = Context::INACTIVE; emit statusChanged(); } + +void GameLoop::mergeSegments() +{ + std::ostringstream mergeCommand; + mergeCommand << "bash -c '"; + mergeCommand << MERGE_HELPER_SCRIPT; + mergeCommand << "' -- "; + mergeCommand << context->config.dumpfile; + sleep(2); //make sure encode has time to finish before merging + system(mergeCommand.str().c_str()); +} diff --git a/src/program/GameLoop.h b/src/program/GameLoop.h index d84abbde..65426f6a 100644 --- a/src/program/GameLoop.h +++ b/src/program/GameLoop.h @@ -91,6 +91,8 @@ class GameLoop : public QObject { bool haveFocus(); void loopExit(); + + void mergeSegments(); signals: void statusChanged(); diff --git a/src/program/MergeHelperScript.h b/src/program/MergeHelperScript.h new file mode 100644 index 00000000..0710b72a --- /dev/null +++ b/src/program/MergeHelperScript.h @@ -0,0 +1,54 @@ +/* + Copyright 2015-2019 Clément Gallet + + This file is part of libTAS. + + libTAS 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. + + libTAS 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 libTAS. If not, see . + */ + +#ifndef MERGE_HELPER_SCRIPT_HEADER +#define MERGE_HELPER_SCRIPT_HEADER + +/* Embeds Bash helper script as a C++11 raw string. + * + * This avoids having to cart around the script as a separate file. + * + * A "raw" string also avoids having to deal with escape sequences. + * However, if your syntax highlighter isn't aware of raw strings, + * then this may look a bit like a train wreck. */ + + /*try to avoid using single-quoted strings within the script, it may make it harder to run later.*/ + +const static char* MERGE_HELPER_SCRIPT = R"( + +# absolute path to the first video (eg. /home/user/tasproject01/video.avi) is passed as command line argument 1 + +VID_PATH=$1 +VID_EXT=$(echo $VID_PATH | sed "s/^.*\././g") +VID_DIR=$(dirname $VID_PATH) +VID_NAME=$(basename -s $VID_EXT $VID_PATH) + +getChunks(){ + for i in $(ls -v "$VID_DIR"/"$VID_NAME"_*"$VID_EXT") + do + echo file $i + done +} + +sync +ffmpeg -f concat -safe 0 -i <(getChunks) -c copy -y $VID_DIR/$VID_NAME-merged.mkv + +)"; + +#endif diff --git a/src/program/ui/EncodeWindow.cpp b/src/program/ui/EncodeWindow.cpp index c1bfb186..d3d8b51d 100644 --- a/src/program/ui/EncodeWindow.cpp +++ b/src/program/ui/EncodeWindow.cpp @@ -71,6 +71,9 @@ EncodeWindow::EncodeWindow(Context* c, QWidget *parent, Qt::WindowFlags flags) : connect(audioBitrate, static_cast(&QSpinBox::valueChanged), this, &EncodeWindow::slotUpdate); ffmpegOptions = new QLineEdit(); + + mergeCheck = new QCheckBox("Automatically merge dump segments"); + connect(mergeCheck, &QAbstractButton::clicked, this, &EncodeWindow::slotMerge); QGroupBox *codecGroupBox = new QGroupBox(tr("Encode codec settings")); QGridLayout *encodeCodecLayout = new QGridLayout; @@ -86,6 +89,8 @@ EncodeWindow::EncodeWindow(Context* c, QWidget *parent, Qt::WindowFlags flags) : encodeCodecLayout->addWidget(new QLabel(tr("ffmpeg options:")), 2, 0); encodeCodecLayout->addWidget(ffmpegOptions, 2, 1, 1, 4); + encodeCodecLayout->addWidget(mergeCheck, 3, 1, 1, 4); + encodeCodecLayout->setColumnMinimumWidth(2, 50); encodeCodecLayout->setColumnStretch(2, 1); @@ -128,6 +133,8 @@ void EncodeWindow::update_config() /* Set ffmpeg options */ ffmpegOptions->setText(context->config.ffmpegoptions.c_str()); + + mergeCheck->setChecked(context->config.merge_dump_segments); if (context->config.ffmpegoptions.empty()) { slotUpdate(); @@ -167,3 +174,8 @@ void EncodeWindow::slotBrowseEncodePath() if (!filename.isNull()) encodePath->setText(filename); } + +void EncodeWindow::slotMerge(bool checked) +{ + context->config.merge_dump_segments = checked; +} diff --git a/src/program/ui/EncodeWindow.h b/src/program/ui/EncodeWindow.h index a3f71cf3..533ebd0e 100644 --- a/src/program/ui/EncodeWindow.h +++ b/src/program/ui/EncodeWindow.h @@ -25,6 +25,8 @@ #include #include #include +#include + #include "../Context.h" @@ -47,11 +49,14 @@ class EncodeWindow : public QDialog { QComboBox *audioChoice; QSpinBox *audioBitrate; QLineEdit *ffmpegOptions; + QCheckBox *mergeCheck; + private slots: void slotBrowseEncodePath(); void slotUpdate(); void slotOk(); + void slotMerge(bool checked); }; #endif