From 6eb959e406d0412c8da9af153ec956bcb3dc9995 Mon Sep 17 00:00:00 2001 From: lordmulder Date: Wed, 1 Dec 2010 23:14:47 +0100 Subject: [PATCH] Added support for dedicated decoders. Only Vorbis and MP3 so far. --- LameXP.vcproj | 120 +++++++++++++++++++++++++-- src/Config.h | 2 +- src/Decoder_Abstract.cpp | 39 +++++++++ src/Decoder_Abstract.h | 37 +++++++++ src/Decoder_MP3.cpp | 142 ++++++++++++++++++++++++++++++++ src/Decoder_MP3.h | 37 +++++++++ src/Decoder_Vorbis.cpp | 126 ++++++++++++++++++++++++++++ src/Decoder_Vorbis.h | 37 +++++++++ src/Dialog_MainWindow.cpp | 1 - src/Encoder_Abstract.cpp | 101 ----------------------- src/Encoder_Abstract.h | 19 +---- src/Encoder_MP3.cpp | 25 +++--- src/Encoder_MP3.h | 2 +- src/Encoder_Vorbis.cpp | 18 ++-- src/Encoder_Vorbis.h | 2 +- src/Registry_Decoder.cpp | 38 +++++++++ src/Registry_Decoder.h | 31 +++++++ src/Thread_Process.cpp | 83 +++++++++++++++++-- src/Thread_Process.h | 12 +++ src/Tool_Abstract.cpp | 167 ++++++++++++++++++++++++++++++++++++++ src/Tool_Abstract.h | 48 +++++++++++ 21 files changed, 931 insertions(+), 156 deletions(-) create mode 100644 src/Decoder_Abstract.cpp create mode 100644 src/Decoder_Abstract.h create mode 100644 src/Decoder_MP3.cpp create mode 100644 src/Decoder_MP3.h create mode 100644 src/Decoder_Vorbis.cpp create mode 100644 src/Decoder_Vorbis.h create mode 100644 src/Registry_Decoder.cpp create mode 100644 src/Registry_Decoder.h create mode 100644 src/Tool_Abstract.cpp create mode 100644 src/Tool_Abstract.h diff --git a/LameXP.vcproj b/LameXP.vcproj index 73bd0112..62029661 100644 --- a/LameXP.vcproj +++ b/LameXP.vcproj @@ -290,6 +290,22 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + + + + + + + @@ -374,6 +390,10 @@ RelativePath=".\src\Model_Settings.cpp" > + + @@ -394,6 +414,10 @@ RelativePath=".\src\Thread_Process.cpp" > + + + + + + + + + + + + + + + @@ -617,7 +679,7 @@ @@ -627,7 +689,7 @@ @@ -637,7 +699,7 @@ @@ -904,6 +966,10 @@ RelativePath=".\src\Model_Settings.h" > + + @@ -1082,12 +1148,50 @@ /> + + + + + + + + + + + + + @@ -1164,6 +1268,10 @@ RelativePath=".\tmp\MOC_Thread_Process.cpp" > + + @@ -1477,7 +1585,7 @@ @@ -1487,7 +1595,7 @@ @@ -1497,7 +1605,7 @@ diff --git a/src/Config.h b/src/Config.h index 0c55f6dd..9d5bd259 100644 --- a/src/Config.h +++ b/src/Config.h @@ -25,7 +25,7 @@ #define VER_LAMEXP_MAJOR 4 #define VER_LAMEXP_MINOR_HI 0 #define VER_LAMEXP_MINOR_LO 0 -#define VER_LAMEXP_BUILD 105 +#define VER_LAMEXP_BUILD 110 #define VER_LAMEXP_SUFFIX TechPreview /* diff --git a/src/Decoder_Abstract.cpp b/src/Decoder_Abstract.cpp new file mode 100644 index 00000000..685d2e6f --- /dev/null +++ b/src/Decoder_Abstract.cpp @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#include "Decoder_Abstract.h" + +AbstractDecoder::AbstractDecoder(void) +{ +} + +AbstractDecoder::~AbstractDecoder(void) +{ +} + +/* + * Default implementation + */ + +bool AbstractDecoder::isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion) +{ + return false; +} diff --git a/src/Decoder_Abstract.h b/src/Decoder_Abstract.h new file mode 100644 index 00000000..581114b5 --- /dev/null +++ b/src/Decoder_Abstract.h @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "Tool_Abstract.h" + +class AbstractDecoder : public AbstractTool +{ + Q_OBJECT + +public: + AbstractDecoder(void); + ~AbstractDecoder(void); + + //Internal decoder API + virtual bool decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag) = 0; + static bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion); +}; diff --git a/src/Decoder_MP3.cpp b/src/Decoder_MP3.cpp new file mode 100644 index 00000000..72451855 --- /dev/null +++ b/src/Decoder_MP3.cpp @@ -0,0 +1,142 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#include "Decoder_MP3.h" + +#include "Global.h" + +#include +#include +#include + +MP3Decoder::MP3Decoder(void) +: + m_binary(lamexp_lookup_tool("mpg123.exe")) +{ + if(m_binary.isEmpty()) + { + throw "Error initializing MPG123 decoder. Tool 'oggdec.exe' is not registred!"; + } +} + +MP3Decoder::~MP3Decoder(void) +{ +} + +bool MP3Decoder::decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag) +{ + QProcess process; + QStringList args; + + args << "-v" << "-w" << QDir::toNativeSeparators(outputFile); + args << QDir::toNativeSeparators(sourceFile); + + if(!startProcess(process, m_binary, args)) + { + return false; + } + + bool bTimeout = false; + bool bAborted = false; + + QRegExp regExp("\\s+Time:\\s+(\\d+):(\\d+)\\.(\\d+)\\s+\\[(\\d+):(\\d+)\\.(\\d+)\\],"); + + while(process.state() != QProcess::NotRunning) + { + if(*abortFlag) + { + process.kill(); + bAborted = true; + emit messageLogged("\nABORTED BY USER !!!"); + break; + } + process.waitForReadyRead(); + if(!process.bytesAvailable() && process.state() == QProcess::Running) + { + process.kill(); + qWarning("mpg123 process timed out <-- killing!"); + bTimeout = true; + break; + } + while(process.bytesAvailable() > 0) + { + QByteArray line = process.readLine(); + QString text = QString::fromUtf8(line.constData()).simplified(); + if(regExp.lastIndexIn(text) >= 0) + { + int values[6]; + for(int i = 0; i < 6; i++) + { + bool ok = false; + int temp = regExp.cap(i+1).toInt(&ok); + values[i] = (ok ? temp : 0); + } + int timeDone = (60 * values[0]) + values[1]; + int timeLeft = (60 * values[3]) + values[4]; + if(timeDone > 0 || timeLeft > 0) + { + statusUpdated(static_cast((static_cast(timeDone) / static_cast(timeDone + timeLeft)) * 100.0)); + } + } + else if(!text.isEmpty()) + { + emit messageLogged(text); + } + } + } + + process.waitForFinished(); + if(process.state() != QProcess::NotRunning) + { + process.kill(); + process.waitForFinished(-1); + } + + emit statusUpdated(100); + emit messageLogged(QString().sprintf("\nExited with code: 0x%04X", process.exitCode())); + + if(bTimeout || bAborted || process.exitStatus() != QProcess::NormalExit) + { + return false; + } + + return true; +} + +bool MP3Decoder::isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion) +{ + if(containerType.compare("MPEG Audio", Qt::CaseInsensitive) == 0 || containerType.compare("Wave", Qt::CaseInsensitive) == 0) + { + if(formatType.compare("MPEG Audio", Qt::CaseInsensitive) == 0) + { + if(formatProfile.compare("Layer 3", Qt::CaseInsensitive) == 0 || formatProfile.compare("Layer 2", Qt::CaseInsensitive) == 0) + { + if(formatVersion.compare("Version 1", Qt::CaseInsensitive) == 0 || formatVersion.compare("Version 2", Qt::CaseInsensitive) == 0) + { + return true; + } + } + } + } + + return false; +} + diff --git a/src/Decoder_MP3.h b/src/Decoder_MP3.h new file mode 100644 index 00000000..6ebb7637 --- /dev/null +++ b/src/Decoder_MP3.h @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "Decoder_Abstract.h" + +class MP3Decoder : public AbstractDecoder +{ +public: + MP3Decoder(void); + ~MP3Decoder(void); + + virtual bool decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag); + static bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion); + +private: + const QString m_binary; +}; diff --git a/src/Decoder_Vorbis.cpp b/src/Decoder_Vorbis.cpp new file mode 100644 index 00000000..9e94808d --- /dev/null +++ b/src/Decoder_Vorbis.cpp @@ -0,0 +1,126 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#include "Decoder_Vorbis.h" + +#include "Global.h" + +#include +#include +#include + +VorbisDecoder::VorbisDecoder(void) +: + m_binary(lamexp_lookup_tool("oggdec.exe")) +{ + if(m_binary.isEmpty()) + { + throw "Error initializing Vorbis decoder. Tool 'oggdec.exe' is not registred!"; + } +} + +VorbisDecoder::~VorbisDecoder(void) +{ +} + +bool VorbisDecoder::decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag) +{ + QProcess process; + QStringList args; + + args << "-w" << pathToShort(QDir::toNativeSeparators(outputFile)); + args << pathToShort(QDir::toNativeSeparators(sourceFile)); + + if(!startProcess(process, m_binary, args)) + { + return false; + } + + bool bTimeout = false; + bool bAborted = false; + + QRegExp regExp(" (\\d+)% decoded."); + + while(process.state() != QProcess::NotRunning) + { + if(*abortFlag) + { + process.kill(); + bAborted = true; + emit messageLogged("\nABORTED BY USER !!!"); + break; + } + process.waitForReadyRead(); + if(!process.bytesAvailable() && process.state() == QProcess::Running) + { + process.kill(); + qWarning("OggDec process timed out <-- killing!"); + bTimeout = true; + break; + } + while(process.bytesAvailable() > 0) + { + QByteArray line = process.readLine(); + QString text = QString::fromUtf8(line.constData()).simplified(); + if(regExp.lastIndexIn(text) >= 0) + { + bool ok = false; + int progress = regExp.cap(1).toInt(&ok); + if(ok) emit statusUpdated(progress); + } + else if(!text.isEmpty()) + { + emit messageLogged(text); + } + } + } + + process.waitForFinished(); + if(process.state() != QProcess::NotRunning) + { + process.kill(); + process.waitForFinished(-1); + } + + emit statusUpdated(100); + emit messageLogged(QString().sprintf("\nExited with code: 0x%04X", process.exitCode())); + + if(bTimeout || bAborted || process.exitStatus() != QProcess::NormalExit || QFileInfo(outputFile).size() == 0) + { + return false; + } + + return true; +} + +bool VorbisDecoder::isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion) +{ + if(containerType.compare("OGG", Qt::CaseInsensitive) == 0) + { + if(formatType.compare("Vorbis", Qt::CaseInsensitive) == 0) + { + return true; + } + } + + return false; +} + diff --git a/src/Decoder_Vorbis.h b/src/Decoder_Vorbis.h new file mode 100644 index 00000000..c856450e --- /dev/null +++ b/src/Decoder_Vorbis.h @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "Decoder_Abstract.h" + +class VorbisDecoder : public AbstractDecoder +{ +public: + VorbisDecoder(void); + ~VorbisDecoder(void); + + virtual bool decode(const QString &sourceFile, const QString &outputFile, volatile bool *abortFlag); + static bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion); + +private: + const QString m_binary; +}; diff --git a/src/Dialog_MainWindow.cpp b/src/Dialog_MainWindow.cpp index a4cfc1e2..b229e7be 100644 --- a/src/Dialog_MainWindow.cpp +++ b/src/Dialog_MainWindow.cpp @@ -34,7 +34,6 @@ #include "Model_Settings.h" #include "Model_FileList.h" #include "Model_FileSystem.h" -#include "Encoder_MP3.h" //Qt includes #include diff --git a/src/Encoder_Abstract.cpp b/src/Encoder_Abstract.cpp index 103a1ba3..e8aabd8c 100644 --- a/src/Encoder_Abstract.cpp +++ b/src/Encoder_Abstract.cpp @@ -21,57 +21,10 @@ #include "Encoder_Abstract.h" -#include -#include -#include -#include -#include #include -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define min(a,b) (((a) < (b)) ? (a) : (b)) - -QMutex *AbstractEncoder::m_mutex_startProcess = NULL; -HANDLE AbstractEncoder::m_handle_jobObject = NULL; - AbstractEncoder::AbstractEncoder(void) { - typedef HANDLE (WINAPI *CreateJobObjectFun)(__in_opt LPSECURITY_ATTRIBUTES lpJobAttributes, __in_opt LPCSTR lpName); - typedef BOOL (WINAPI *SetInformationJobObjectFun)(__in HANDLE hJob, __in JOBOBJECTINFOCLASS JobObjectInformationClass, __in_bcount(cbJobObjectInformationLength) LPVOID lpJobObjectInformation, __in DWORD cbJobObjectInformationLength); - - static CreateJobObjectFun CreateJobObjectPtr = NULL; - static SetInformationJobObjectFun SetInformationJobObjectPtr = NULL; - - if(!m_mutex_startProcess) - { - m_mutex_startProcess = new QMutex(); - } - - if(!m_handle_jobObject) - { - if(!CreateJobObjectPtr || !SetInformationJobObjectPtr) - { - QLibrary Kernel32Lib("kernel32.dll"); - CreateJobObjectPtr = (CreateJobObjectFun) Kernel32Lib.resolve("CreateJobObjectA"); - SetInformationJobObjectPtr = (SetInformationJobObjectFun) Kernel32Lib.resolve("SetInformationJobObject"); - } - if(CreateJobObjectPtr && SetInformationJobObjectPtr) - { - m_handle_jobObject = CreateJobObjectPtr(NULL, NULL); - if(m_handle_jobObject == INVALID_HANDLE_VALUE) - { - m_handle_jobObject = NULL; - } - if(m_handle_jobObject) - { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobExtendedLimitInfo; - memset(&jobExtendedLimitInfo, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); - jobExtendedLimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION; - SetInformationJobObjectPtr(m_handle_jobObject, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); - } - } - } - m_configBitrate = 0; m_configRCMode = 0; } @@ -86,57 +39,3 @@ AbstractEncoder::~AbstractEncoder(void) void AbstractEncoder::setBitrate(int bitrate) { m_configBitrate = max(0, bitrate); } void AbstractEncoder::setRCMode(int mode) { m_configRCMode = max(0, mode); } - -/* - * Auxiliary functions - */ - -bool AbstractEncoder::startProcess(QProcess &process, const QString &program, const QStringList &args) -{ - typedef BOOL (WINAPI *AssignProcessToJobObjectFun)(__in HANDLE hJob, __in HANDLE hProcess); - static AssignProcessToJobObjectFun AssignProcessToJobObjectPtr = NULL; - - QMutexLocker lock(m_mutex_startProcess); - - emit messageLogged(commandline2string(program, args) + "\n"); - - if(!AssignProcessToJobObjectPtr) - { - QLibrary Kernel32Lib("kernel32.dll"); - AssignProcessToJobObjectPtr = (AssignProcessToJobObjectFun) Kernel32Lib.resolve("AssignProcessToJobObject"); - } - - process.setProcessChannelMode(QProcess::MergedChannels); - process.setReadChannel(QProcess::StandardOutput); - process.start(program, args); - - if(process.waitForStarted()) - { - - if(AssignProcessToJobObjectPtr) - { - AssignProcessToJobObjectPtr(m_handle_jobObject, process.pid()->hProcess); - } - if(!SetPriorityClass(process.pid()->hProcess, BELOW_NORMAL_PRIORITY_CLASS)) - { - SetPriorityClass(process.pid()->hProcess, IDLE_PRIORITY_CLASS); - } - lock.unlock(); - emit statusUpdated(0); - return true; - } - - return false; -} - -QString AbstractEncoder::commandline2string(const QString &program, const QStringList &arguments) -{ - QString commandline = (program.contains(' ') ? QString("\"%1\"").arg(program) : program); - - for(int i = 0; i < arguments.count(); i++) - { - commandline += (arguments.at(i).contains(' ') ? QString(" \"%1\"").arg(arguments.at(i)) : QString(" %1").arg(arguments.at(i))); - } - - return commandline; -} diff --git a/src/Encoder_Abstract.h b/src/Encoder_Abstract.h index ec9fcfe9..98e72882 100644 --- a/src/Encoder_Abstract.h +++ b/src/Encoder_Abstract.h @@ -21,15 +21,14 @@ #pragma once +#include "Tool_Abstract.h" #include "Model_AudioFile.h" -#include - class QProcess; class QStringList; class QMutex; -class AbstractEncoder : public QObject +class AbstractEncoder : public AbstractTool { Q_OBJECT @@ -38,7 +37,7 @@ public: ~AbstractEncoder(void); //Internal encoder API - virtual bool encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag) = 0; + virtual bool encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag) = 0; virtual bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion) = 0; virtual QString extension(void) = 0; @@ -46,19 +45,7 @@ public: void setBitrate(int bitrate); void setRCMode(int mode); - //Auxiliary functions - bool startProcess(QProcess &process, const QString &program, const QStringList &args); - static QString commandline2string(const QString &program, const QStringList &arguments); - -signals: - void statusUpdated(int progress); - void messageLogged(const QString &line); - protected: int m_configBitrate; int m_configRCMode; - -private: - static QMutex *m_mutex_startProcess; - static void *m_handle_jobObject; }; diff --git a/src/Encoder_MP3.cpp b/src/Encoder_MP3.cpp index e00cd395..2b983d51 100644 --- a/src/Encoder_MP3.cpp +++ b/src/Encoder_MP3.cpp @@ -27,11 +27,11 @@ #include #include -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#define min(a,b) (((a) < (b)) ? (a) : (b)) #define IS_UNICODE(STR) (qstricmp(STR.toUtf8().constData(), QString::fromLocal8Bit(STR.toLocal8Bit()).toUtf8().constData())) -MP3Encoder::MP3Encoder(void) : m_binary(lamexp_lookup_tool("lame.exe")) +MP3Encoder::MP3Encoder(void) +: + m_binary(lamexp_lookup_tool("lame.exe")) { if(m_binary.isEmpty()) { @@ -43,10 +43,9 @@ MP3Encoder::~MP3Encoder(void) { } -bool MP3Encoder::encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag) +bool MP3Encoder::encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag) { QProcess process; - const QString baseName = QFileInfo(outputFile).fileName(); QStringList args; args << "--nohist"; @@ -69,17 +68,17 @@ bool MP3Encoder::encode(const AudioFileModel &sourceFile, const QString &outputF break; } - if(!sourceFile.fileName().isEmpty()) args << (IS_UNICODE(sourceFile.fileName()) ? "--uTitle" : "--lTitle") << sourceFile.fileName(); - if(!sourceFile.fileArtist().isEmpty()) args << (IS_UNICODE(sourceFile.fileArtist()) ? "--uArtist" : "--lArtist") << sourceFile.fileArtist(); - if(!sourceFile.fileAlbum().isEmpty()) args << (IS_UNICODE(sourceFile.fileAlbum()) ? "--uAlbum" : "--lAlbum") << sourceFile.fileAlbum(); - if(!sourceFile.fileGenre().isEmpty()) args << (IS_UNICODE(sourceFile.fileGenre()) ? "--uGenre" : "--lGenre") << sourceFile.fileGenre(); - if(!sourceFile.fileComment().isEmpty()) args << (IS_UNICODE(sourceFile.fileComment()) ? "--uComment" : "--lComment") << sourceFile.fileComment(); - if(sourceFile.fileYear()) args << "--ty" << QString::number(sourceFile.fileYear()); - if(sourceFile.filePosition()) args << "--tn" << QString::number(sourceFile.filePosition()); + if(!metaInfo.fileName().isEmpty()) args << (IS_UNICODE(metaInfo.fileName()) ? "--uTitle" : "--lTitle") << metaInfo.fileName(); + if(!metaInfo.fileArtist().isEmpty()) args << (IS_UNICODE(metaInfo.fileArtist()) ? "--uArtist" : "--lArtist") << metaInfo.fileArtist(); + if(!metaInfo.fileAlbum().isEmpty()) args << (IS_UNICODE(metaInfo.fileAlbum()) ? "--uAlbum" : "--lAlbum") << metaInfo.fileAlbum(); + if(!metaInfo.fileGenre().isEmpty()) args << (IS_UNICODE(metaInfo.fileGenre()) ? "--uGenre" : "--lGenre") << metaInfo.fileGenre(); + if(!metaInfo.fileComment().isEmpty()) args << (IS_UNICODE(metaInfo.fileComment()) ? "--uComment" : "--lComment") << metaInfo.fileComment(); + if(metaInfo.fileYear()) args << "--ty" << QString::number(metaInfo.fileYear()); + if(metaInfo.filePosition()) args << "--tn" << QString::number(metaInfo.filePosition()); //args << "--tv" << QString().sprintf("Encoder=LameXP v%d.%02d.%04d [%s]", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build(), lamexp_version_release()); - args << QDir::toNativeSeparators(sourceFile.filePath()); + args << QDir::toNativeSeparators(sourceFile); args << QDir::toNativeSeparators(outputFile); if(!startProcess(process, m_binary, args)) diff --git a/src/Encoder_MP3.h b/src/Encoder_MP3.h index bed3a6e8..860cc8ad 100644 --- a/src/Encoder_MP3.h +++ b/src/Encoder_MP3.h @@ -33,7 +33,7 @@ public: MP3Encoder(void); ~MP3Encoder(void); - virtual bool encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag); + virtual bool encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag); virtual bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion); virtual QString extension(void); diff --git a/src/Encoder_Vorbis.cpp b/src/Encoder_Vorbis.cpp index 525d7db0..befd54c3 100644 --- a/src/Encoder_Vorbis.cpp +++ b/src/Encoder_Vorbis.cpp @@ -47,7 +47,7 @@ VorbisEncoder::~VorbisEncoder(void) { } -bool VorbisEncoder::encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag) +bool VorbisEncoder::encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag) { QProcess process; QStringList args; @@ -68,18 +68,18 @@ bool VorbisEncoder::encode(const AudioFileModel &sourceFile, const QString &outp break; } - if(!sourceFile.fileName().isEmpty()) args << "-t" << sourceFile.fileName(); - if(!sourceFile.fileArtist().isEmpty()) args << "-a" << sourceFile.fileArtist(); - if(!sourceFile.fileAlbum().isEmpty()) args << "-l" << sourceFile.fileAlbum(); - if(!sourceFile.fileGenre().isEmpty()) args << "-G" << sourceFile.fileGenre(); - if(!sourceFile.fileComment().isEmpty()) args << "-c" << QString("comment=%1").arg(sourceFile.fileComment()); - if(sourceFile.fileYear()) args << "-d" << QString::number(sourceFile.fileYear()); - if(sourceFile.filePosition()) args << "-N" << QString::number(sourceFile.filePosition()); + if(!metaInfo.fileName().isEmpty()) args << "-t" << metaInfo.fileName(); + if(!metaInfo.fileArtist().isEmpty()) args << "-a" << metaInfo.fileArtist(); + if(!metaInfo.fileAlbum().isEmpty()) args << "-l" << metaInfo.fileAlbum(); + if(!metaInfo.fileGenre().isEmpty()) args << "-G" << metaInfo.fileGenre(); + if(!metaInfo.fileComment().isEmpty()) args << "-c" << QString("comment=%1").arg(metaInfo.fileComment()); + if(metaInfo.fileYear()) args << "-d" << QString::number(metaInfo.fileYear()); + if(metaInfo.filePosition()) args << "-N" << QString::number(metaInfo.filePosition()); //args << "--tv" << QString().sprintf("Encoder=LameXP v%d.%02d.%04d [%s]", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build(), lamexp_version_release()); args << "-o" << QDir::toNativeSeparators(outputFile); - args << QDir::toNativeSeparators(sourceFile.filePath()); + args << QDir::toNativeSeparators(sourceFile); if(!startProcess(process, binary, args)) { diff --git a/src/Encoder_Vorbis.h b/src/Encoder_Vorbis.h index 00bac598..aa8fa679 100644 --- a/src/Encoder_Vorbis.h +++ b/src/Encoder_Vorbis.h @@ -33,7 +33,7 @@ public: VorbisEncoder(void); ~VorbisEncoder(void); - virtual bool encode(const AudioFileModel &sourceFile, const QString &outputFile, volatile bool *abortFlag); + virtual bool encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag); virtual bool isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion); virtual QString extension(void); diff --git a/src/Registry_Decoder.cpp b/src/Registry_Decoder.cpp new file mode 100644 index 00000000..59cfe90b --- /dev/null +++ b/src/Registry_Decoder.cpp @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#include "Registry_Decoder.h" + +#include "Decoder_Abstract.h" +#include "Decoder_MP3.h" +#include "Decoder_Vorbis.h" + +#include + +#define PROBE_DECODER(DEC) if(DEC::isFormatSupported(containerType, containerProfile, formatType, formatProfile, formatVersion)) { return new DEC(); } + +AbstractDecoder *DecoderRegistry::lookup(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion) +{ + PROBE_DECODER(MP3Decoder); + PROBE_DECODER(VorbisDecoder); + return NULL; +} + diff --git a/src/Registry_Decoder.h b/src/Registry_Decoder.h new file mode 100644 index 00000000..d7572e4f --- /dev/null +++ b/src/Registry_Decoder.h @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +class QString; +class AbstractDecoder; + +class DecoderRegistry +{ +public: + static AbstractDecoder *lookup(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion); +}; diff --git a/src/Thread_Process.cpp b/src/Thread_Process.cpp index 958fdce1..5b72e7db 100644 --- a/src/Thread_Process.cpp +++ b/src/Thread_Process.cpp @@ -25,7 +25,8 @@ #include "Model_AudioFile.h" #include "Model_Progress.h" #include "Encoder_Abstract.h" - +#include "Decoder_Abstract.h" +#include "Registry_Decoder.h" #include "Model_Settings.h" #include @@ -58,10 +59,17 @@ ProcessThread::ProcessThread(const AudioFileModel &audioFile, const QString &out connect(m_encoder, SIGNAL(statusUpdated(int)), this, SLOT(handleUpdate(int)), Qt::DirectConnection); connect(m_encoder, SIGNAL(messageLogged(QString)), this, SLOT(handleMessage(QString)), Qt::DirectConnection); + + m_currentStep = UnknownStep; } ProcessThread::~ProcessThread(void) { + while(!m_tempFiles.isEmpty()) + { + QFile::remove(m_tempFiles.takeFirst()); + } + LAMEXP_DELETE(m_encoder); } @@ -84,10 +92,12 @@ void ProcessThread::run() void ProcessThread::processFile() { m_aborted = false; + bool bSuccess = true; qDebug("Process thread %s has started.", m_jobId.toString().toLatin1().constData()); emit processStateInitialized(m_jobId, QFileInfo(m_audioFile.filePath()).fileName(), "Starting...", ProgressModel::JobRunning); + //Generate output file name QString outFileName = generateOutFileName(); if(outFileName.isEmpty()) { @@ -96,22 +106,53 @@ void ProcessThread::processFile() return; } + QString sourceFile = m_audioFile.filePath(); + + //Decode source file if(!m_encoder->isFormatSupported(m_audioFile.formatContainerType(), m_audioFile.formatContainerProfile(), m_audioFile.formatAudioType(), m_audioFile.formatAudioProfile(), m_audioFile.formatAudioVersion())) { - handleMessage(QString("The format of this file is NOT supported:\n%1\n\nContainer Format:\t%2\nAudio Format:\t%3").arg(m_audioFile.filePath(), m_audioFile.formatContainerInfo(), m_audioFile.formatAudioCompressInfo())); - emit processStateChanged(m_jobId, "Unsupported!", ProgressModel::JobFailed); - emit processStateFinished(m_jobId, outFileName, false); - return; + m_currentStep = DecodingStep; + AbstractDecoder *decoder = DecoderRegistry::lookup(m_audioFile.formatContainerType(), m_audioFile.formatContainerProfile(), m_audioFile.formatAudioType(), m_audioFile.formatAudioProfile(), m_audioFile.formatAudioVersion()); + + if(decoder) + { + QString tempFile = generateTempFileName(); + + connect(decoder, SIGNAL(statusUpdated(int)), this, SLOT(handleUpdate(int)), Qt::DirectConnection); + connect(decoder, SIGNAL(messageLogged(QString)), this, SLOT(handleMessage(QString)), Qt::DirectConnection); + + bSuccess = decoder->decode(sourceFile, tempFile, &m_aborted); + + if(bSuccess) + { + sourceFile = tempFile; + handleMessage("\n-------------------------------\n"); + } + } + else + { + handleMessage(QString("The format of this file is NOT supported:\n%1\n\nContainer Format:\t%2\nAudio Format:\t%3").arg(m_audioFile.filePath(), m_audioFile.formatContainerInfo(), m_audioFile.formatAudioCompressInfo())); + emit processStateChanged(m_jobId, "Unsupported!", ProgressModel::JobFailed); + emit processStateFinished(m_jobId, outFileName, false); + return; + } } - bool bSuccess = m_encoder->encode(m_audioFile, outFileName, &m_aborted); + //Encode audio file + if(bSuccess) + { + m_currentStep = EncodingStep; + bSuccess = m_encoder->encode(sourceFile, m_audioFile, outFileName, &m_aborted); + } + //Make sure output file exists if(bSuccess) { QFileInfo fileInfo(outFileName); bSuccess = fileInfo.exists() && fileInfo.isFile() && (fileInfo.size() > 0); } + //Report result emit processStateChanged(m_jobId, (bSuccess ? "Done." : (m_aborted ? "Aborted!" : "Failed!")), (bSuccess ? ProgressModel::JobComplete : ProgressModel::JobFailed)); emit processStateFinished(m_jobId, outFileName, bSuccess); @@ -124,7 +165,15 @@ void ProcessThread::processFile() void ProcessThread::handleUpdate(int progress) { - emit processStateChanged(m_jobId, QString("Encoding (%1%)").arg(QString::number(progress)), ProgressModel::JobRunning); + switch(m_currentStep) + { + case EncodingStep: + emit processStateChanged(m_jobId, QString("Encoding (%1%)").arg(QString::number(progress)), ProgressModel::JobRunning); + break; + case DecodingStep: + emit processStateChanged(m_jobId, QString("Decoding (%1%)").arg(QString::number(progress)), ProgressModel::JobRunning); + break; + } } void ProcessThread::handleMessage(const QString &line) @@ -200,6 +249,26 @@ QString ProcessThread::generateOutFileName(void) return outFileName; } +QString ProcessThread::generateTempFileName(void) +{ + QMutexLocker lock(m_mutex_genFileName); + QString tempFileName = QString("%1/%2.wav").arg(QDir::tempPath(), QUuid::createUuid().toString()); + + while(QFileInfo(tempFileName).exists()) + { + tempFileName = QString("%1/%2.wav").arg(QDir::tempPath(), QUuid::createUuid().toString()); + } + + QFile file(tempFileName); + if(file.open(QFile::ReadWrite)) + { + file.close(); + } + + m_tempFiles << tempFileName; + return tempFileName; +} + //////////////////////////////////////////////////////////// // EVENTS //////////////////////////////////////////////////////////// diff --git a/src/Thread_Process.h b/src/Thread_Process.h index 6945cab1..7e7eb2fa 100644 --- a/src/Thread_Process.h +++ b/src/Thread_Process.h @@ -23,6 +23,7 @@ #include #include +#include #include "Model_AudioFile.h" #include "Encoder_Abstract.h" @@ -53,14 +54,25 @@ signals: void processMessageLogged(const QUuid &jobId, const QString &line); private: + enum ProcessStep + { + DecodingStep = 0, + FilteringStep = 1, + EncodingStep = 2, + UnknownStep = 3 + }; + void processFile(); QString generateOutFileName(void); + QString generateTempFileName(void); const QUuid m_jobId; AudioFileModel m_audioFile; AbstractEncoder *m_encoder; const QString m_outputDirectory; volatile bool m_aborted; + ProcessStep m_currentStep; + QStringList m_tempFiles; static QMutex *m_mutex_genFileName; }; diff --git a/src/Tool_Abstract.cpp b/src/Tool_Abstract.cpp new file mode 100644 index 00000000..2b599c31 --- /dev/null +++ b/src/Tool_Abstract.cpp @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#include "Tool_Abstract.h" + +#include +#include +#include +#include +#include + +/* + * Win32 API definitions + */ +typedef HANDLE (WINAPI *CreateJobObjectFun)(__in_opt LPSECURITY_ATTRIBUTES lpJobAttributes, __in_opt LPCSTR lpName); +typedef BOOL (WINAPI *SetInformationJobObjectFun)(__in HANDLE hJob, __in JOBOBJECTINFOCLASS JobObjectInformationClass, __in_bcount(cbJobObjectInformationLength) LPVOID lpJobObjectInformation, __in DWORD cbJobObjectInformationLength); +typedef BOOL (WINAPI *AssignProcessToJobObjectFun)(__in HANDLE hJob, __in HANDLE hProcess); + +/* + * Static vars + */ +QMutex *AbstractTool::m_mutex_startProcess = NULL; +HANDLE AbstractTool::m_handle_jobObject = NULL; + +/* + * Constructor + */ +AbstractTool::AbstractTool(void) +{ + static CreateJobObjectFun CreateJobObjectPtr = NULL; + static SetInformationJobObjectFun SetInformationJobObjectPtr = NULL; + + if(!m_mutex_startProcess) + { + m_mutex_startProcess = new QMutex(); + } + + if(!m_handle_jobObject) + { + if(!CreateJobObjectPtr || !SetInformationJobObjectPtr) + { + QLibrary Kernel32Lib("kernel32.dll"); + CreateJobObjectPtr = (CreateJobObjectFun) Kernel32Lib.resolve("CreateJobObjectA"); + SetInformationJobObjectPtr = (SetInformationJobObjectFun) Kernel32Lib.resolve("SetInformationJobObject"); + } + if(CreateJobObjectPtr && SetInformationJobObjectPtr) + { + m_handle_jobObject = CreateJobObjectPtr(NULL, NULL); + if(m_handle_jobObject == INVALID_HANDLE_VALUE) + { + m_handle_jobObject = NULL; + } + if(m_handle_jobObject) + { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobExtendedLimitInfo; + memset(&jobExtendedLimitInfo, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); + jobExtendedLimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION; + SetInformationJobObjectPtr(m_handle_jobObject, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); + } + } + } +} + +/* + * Destructor + */ +AbstractTool::~AbstractTool(void) +{ +} + +/* + * Initialize and launch process object + */ +bool AbstractTool::startProcess(QProcess &process, const QString &program, const QStringList &args) +{ + static AssignProcessToJobObjectFun AssignProcessToJobObjectPtr = NULL; + + QMutexLocker lock(m_mutex_startProcess); + + emit messageLogged(commandline2string(program, args) + "\n"); + + if(!AssignProcessToJobObjectPtr) + { + QLibrary Kernel32Lib("kernel32.dll"); + AssignProcessToJobObjectPtr = (AssignProcessToJobObjectFun) Kernel32Lib.resolve("AssignProcessToJobObject"); + } + + process.setProcessChannelMode(QProcess::MergedChannels); + process.setReadChannel(QProcess::StandardOutput); + process.start(program, args); + + if(process.waitForStarted()) + { + + if(AssignProcessToJobObjectPtr) + { + AssignProcessToJobObjectPtr(m_handle_jobObject, process.pid()->hProcess); + } + if(!SetPriorityClass(process.pid()->hProcess, BELOW_NORMAL_PRIORITY_CLASS)) + { + SetPriorityClass(process.pid()->hProcess, IDLE_PRIORITY_CLASS); + } + lock.unlock(); + emit statusUpdated(0); + return true; + } + + return false; +} + +/* + * Convert program arguments to single string + */ +QString AbstractTool::commandline2string(const QString &program, const QStringList &arguments) +{ + QString commandline = (program.contains(' ') ? QString("\"%1\"").arg(program) : program); + + for(int i = 0; i < arguments.count(); i++) + { + commandline += (arguments.at(i).contains(' ') ? QString(" \"%1\"").arg(arguments.at(i)) : QString(" %1").arg(arguments.at(i))); + } + + return commandline; +} + +/* + * Convert long path to short path + */ +QString AbstractTool::pathToShort(const QString &longPath) +{ + QString shortPath; + DWORD buffSize = GetShortPathNameW(reinterpret_cast(longPath.utf16()), NULL, NULL); + + if(buffSize > 0) + { + wchar_t *buffer = new wchar_t[buffSize]; + DWORD result = GetShortPathNameW(reinterpret_cast(longPath.utf16()), buffer, buffSize); + + if(result > 0 && result < buffSize) + { + shortPath = QString::fromUtf16(reinterpret_cast(buffer)); + } + + delete[] buffer; + } + + return (shortPath.isEmpty() ? longPath : shortPath); +} + diff --git a/src/Tool_Abstract.h b/src/Tool_Abstract.h new file mode 100644 index 00000000..902d592f --- /dev/null +++ b/src/Tool_Abstract.h @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////// +// LameXP - Audio Encoder Front-End +// Copyright (C) 2004-2010 LoRd_MuldeR +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +class QMutex; +class QProcess; + +class AbstractTool : public QObject +{ + Q_OBJECT + +public: + AbstractTool(void); + ~AbstractTool(void); + + bool startProcess(QProcess &process, const QString &program, const QStringList &args); + static QString commandline2string(const QString &program, const QStringList &arguments); + static QString AbstractTool::pathToShort(const QString &longPath); + +signals: + void statusUpdated(int progress); + void messageLogged(const QString &line); + +private: + static QMutex *m_mutex_startProcess; + static void *m_handle_jobObject; +};