0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 13:08:50 +02:00
obs-studio/obs/window-remux.cpp
Palana 3dc1b7f3d5 Fix memory leak when opening and closing remux window without remuxing
The remuxer thread was only started if there was an actual remux job,
which resulted in the remuxer thread not being able to call the worker's
destructor (because it wasn't running)
2014-10-13 20:09:44 +02:00

228 lines
5.2 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);
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();
}
void OBSRemux::BrowseInput()
{
QString path = ui->sourceFile->text();
if (path.isEmpty())
path = recPath;
path = QFileDialog::getOpenFileName(this,
QTStr("Remux.SelectRecording"), path,
QTStr("Remux.RecordingPattern"));
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, "(*.mp4)");
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);
}