obs-studio/UI/window-remux.cpp

233 lines
5.3 KiB
C++

/******************************************************************************
Copyright (C) 2014 by Ruwen Hahn <palana@stunned.de>
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 2 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 "window-remux.hpp"
#include "obs-app.hpp"
#include <QCloseEvent>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include "qt-wrappers.hpp"
#include <memory>
#include <cmath>
using namespace std;
OBSRemux::OBSRemux(const char *path, QWidget *parent)
: QDialog (parent),
worker (new RemuxWorker),
ui (new Ui::OBSRemux),
recPath (path)
{
ui->setupUi(this);
ui->progressBar->setVisible(false);
ui->remux->setEnabled(false);
ui->targetFile->setEnabled(false);
ui->browseTarget->setEnabled(false);
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(1000);
ui->progressBar->setValue(0);
installEventFilter(CreateShortcutFilter());
connect(ui->browseSource, &QPushButton::clicked,
[&]() { BrowseInput(); });
connect(ui->browseTarget, &QPushButton::clicked,
[&]() { BrowseOutput(); });
connect(ui->remux, &QPushButton::clicked, [&]() { Remux(); });
connect(ui->sourceFile, &QLineEdit::textChanged,
this, &OBSRemux::inputChanged);
worker->moveToThread(&remuxer);
remuxer.start();
//gcc-4.8 can't use QPointer<RemuxWorker> below
RemuxWorker *worker_ = worker;
connect(worker_, &RemuxWorker::updateProgress,
this, &OBSRemux::updateProgress);
connect(&remuxer, &QThread::finished, worker_, &QObject::deleteLater);
connect(worker_, &RemuxWorker::remuxFinished,
this, &OBSRemux::remuxFinished);
connect(this, &OBSRemux::remux, worker_, &RemuxWorker::remux);
}
bool OBSRemux::Stop()
{
if (!worker->job)
return true;
if (QMessageBox::critical(nullptr,
QTStr("Remux.ExitUnfinishedTitle"),
QTStr("Remux.ExitUnfinished"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) ==
QMessageBox::Yes) {
os_event_signal(worker->stop);
return true;
}
return false;
}
OBSRemux::~OBSRemux()
{
Stop();
remuxer.quit();
remuxer.wait();
}
#define RECORDING_PATTERN "(*.flv *.mp4 *.mov *.mkv *.ts *.m3u8)"
void OBSRemux::BrowseInput()
{
QString path = ui->sourceFile->text();
if (path.isEmpty())
path = recPath;
path = QFileDialog::getOpenFileName(this,
QTStr("Remux.SelectRecording"), path,
QTStr("Remux.OBSRecording") + QString(" ") +
RECORDING_PATTERN);
inputChanged(path);
}
void OBSRemux::inputChanged(const QString &path)
{
if (!QFileInfo::exists(path)) {
ui->remux->setEnabled(false);
return;
}
ui->sourceFile->setText(path);
ui->remux->setEnabled(true);
QFileInfo fi(path);
QString mp4 = fi.path() + "/" + fi.baseName() + ".mp4";
ui->targetFile->setText(mp4);
ui->targetFile->setEnabled(true);
ui->browseTarget->setEnabled(true);
}
void OBSRemux::BrowseOutput()
{
QString path(ui->targetFile->text());
path = QFileDialog::getSaveFileName(this, QTStr("Remux.SelectTarget"),
path, RECORDING_PATTERN);
if (path.isEmpty())
return;
ui->targetFile->setText(path);
}
void OBSRemux::Remux()
{
if (QFileInfo::exists(ui->targetFile->text()))
if (QMessageBox::question(this, QTStr("Remux.FileExistsTitle"),
QTStr("Remux.FileExists"),
QMessageBox::Yes | QMessageBox::No) !=
QMessageBox::Yes)
return;
media_remux_job_t mr_job = nullptr;
if (!media_remux_job_create(&mr_job, QT_TO_UTF8(ui->sourceFile->text()),
QT_TO_UTF8(ui->targetFile->text())))
return;
worker->job = job_t(mr_job, media_remux_job_destroy);
worker->lastProgress = 0.f;
ui->progressBar->setVisible(true);
ui->remux->setEnabled(false);
emit remux();
}
void OBSRemux::closeEvent(QCloseEvent *event)
{
if (!Stop())
event->ignore();
else
QDialog::closeEvent(event);
}
void OBSRemux::reject()
{
if (!Stop())
return;
QDialog::reject();
}
void OBSRemux::updateProgress(float percent)
{
ui->progressBar->setValue(percent * 10);
}
void OBSRemux::remuxFinished(bool success)
{
QMessageBox::information(this, QTStr("Remux.FinishedTitle"),
success ?
QTStr("Remux.Finished") : QTStr("Remux.FinishedError"));
worker->job.reset();
ui->progressBar->setVisible(false);
ui->remux->setEnabled(true);
}
RemuxWorker::RemuxWorker()
{
os_event_init(&stop, OS_EVENT_TYPE_MANUAL);
}
RemuxWorker::~RemuxWorker()
{
os_event_destroy(stop);
}
void RemuxWorker::UpdateProgress(float percent)
{
if (abs(lastProgress - percent) < 0.1f)
return;
emit updateProgress(percent);
lastProgress = percent;
}
void RemuxWorker::remux()
{
auto callback = [](void *data, float percent)
{
auto rw = static_cast<RemuxWorker*>(data);
rw->UpdateProgress(percent);
return !!os_event_try(rw->stop);
};
bool success = media_remux_job_process(job.get(), callback, this);
emit remuxFinished(os_event_try(stop) && success);
}