Added support for dedicated decoders. Only Vorbis and MP3 so far.

This commit is contained in:
LoRd_MuldeR 2010-12-01 23:14:47 +01:00
parent c77efc9bdf
commit 6eb959e406
21 changed files with 931 additions and 156 deletions

View File

@ -290,6 +290,22 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\src\Decoder_Abstract.cpp"
>
</File>
<File
RelativePath=".\src\Decoder_MP3.cpp"
>
</File>
<File
RelativePath=".\src\Decoder_MP3.h"
>
</File>
<File
RelativePath=".\src\Decoder_Vorbis.cpp"
>
</File>
<File
RelativePath=".\src\Dialog_About.cpp"
>
@ -374,6 +390,10 @@
RelativePath=".\src\Model_Settings.cpp"
>
</File>
<File
RelativePath=".\src\Registry_Decoder.cpp"
>
</File>
<File
RelativePath=".\src\Thread_FileAnalyzer.cpp"
>
@ -394,6 +414,10 @@
RelativePath=".\src\Thread_Process.cpp"
>
</File>
<File
RelativePath=".\src\Tool_Abstract.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
@ -404,6 +428,44 @@
RelativePath=".\src\Config.h"
>
</File>
<File
RelativePath=".\src\Decoder_Abstract.h"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCustomBuildTool"
Description="MOC &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;"
Outputs="&quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCustomBuildTool"
Description="MOC &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;"
Outputs="&quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_Static|Win32"
>
<Tool
Name="VCCustomBuildTool"
Description="MOC &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;"
Outputs="&quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\src\Decoder_Vorbis.h"
>
</File>
<File
RelativePath=".\src\Dialog_About.h"
>
@ -617,7 +679,7 @@
<Tool
Name="VCCustomBuildTool"
Description="MOC &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
Outputs="&quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
/>
</FileConfiguration>
@ -627,7 +689,7 @@
<Tool
Name="VCCustomBuildTool"
Description="MOC &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
Outputs="&quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
/>
</FileConfiguration>
@ -637,7 +699,7 @@
<Tool
Name="VCCustomBuildTool"
Description="MOC &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
Outputs="&quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
/>
</FileConfiguration>
@ -904,6 +966,10 @@
RelativePath=".\src\Model_Settings.h"
>
</File>
<File
RelativePath=".\src\Registry_Decoder.h"
>
</File>
<File
RelativePath=".\src\Resource.h"
>
@ -1082,12 +1148,50 @@
/>
</FileConfiguration>
</File>
<File
RelativePath=".\src\Tool_Abstract.h"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCustomBuildTool"
Description="MOC &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;"
Outputs="&quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCustomBuildTool"
Description="MOC &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;"
Outputs="&quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_Static|Win32"
>
<Tool
Name="VCCustomBuildTool"
Description="MOC &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; -o &quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot; &quot;$(InputPath)&quot;"
Outputs="&quot;$(SolutionDir)tmp\MOC_$(SafeInputName).cpp&quot;"
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Generated Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath=".\tmp\MOC_Decoder_Abstract.cpp"
>
</File>
<File
RelativePath=".\tmp\MOC_Dialog_About.cpp"
>
@ -1164,6 +1268,10 @@
RelativePath=".\tmp\MOC_Thread_Process.cpp"
>
</File>
<File
RelativePath=".\tmp\MOC_Tool_Abstract.cpp"
>
</File>
<File
RelativePath=".\tmp\RCC_Icons.cpp"
>
@ -1477,7 +1585,7 @@
<Tool
Name="VCCustomBuildTool"
Description="UIC &quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot;"
CommandLine="&quot;$(QTDIR)\bin\uic.exe&quot; -o &quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot; &quot;$(InputPath)&quot;"
CommandLine="&quot;$(QTDIR)\bin\uic.exe&quot; -o &quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
Outputs="&quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot;"
/>
</FileConfiguration>
@ -1487,7 +1595,7 @@
<Tool
Name="VCCustomBuildTool"
Description="UIC &quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot;"
CommandLine="&quot;$(QTDIR)\bin\uic.exe&quot; -o &quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot; &quot;$(InputPath)&quot;"
CommandLine="&quot;$(QTDIR)\bin\uic.exe&quot; -o &quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
Outputs="&quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot;"
/>
</FileConfiguration>
@ -1497,7 +1605,7 @@
<Tool
Name="VCCustomBuildTool"
Description="UIC &quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot;"
CommandLine="&quot;$(QTDIR)\bin\uic.exe&quot; -o &quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot; &quot;$(InputPath)&quot;"
CommandLine="&quot;$(QTDIR)\bin\uic.exe&quot; -o &quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot; &quot;$(InputPath)&quot;&#x0D;&#x0A;"
Outputs="&quot;$(SolutionDir)tmp\UIC_$(SafeInputName).h&quot;"
/>
</FileConfiguration>

View File

@ -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
/*

39
src/Decoder_Abstract.cpp Normal file
View File

@ -0,0 +1,39 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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;
}

37
src/Decoder_Abstract.h Normal file
View File

@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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);
};

142
src/Decoder_MP3.cpp Normal file
View File

@ -0,0 +1,142 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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 <QDir>
#include <QProcess>
#include <QRegExp>
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<int>((static_cast<double>(timeDone) / static_cast<double>(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;
}

37
src/Decoder_MP3.h Normal file
View File

@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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;
};

126
src/Decoder_Vorbis.cpp Normal file
View File

@ -0,0 +1,126 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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 <QDir>
#include <QProcess>
#include <QRegExp>
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;
}

37
src/Decoder_Vorbis.h Normal file
View File

@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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;
};

View File

@ -34,7 +34,6 @@
#include "Model_Settings.h"
#include "Model_FileList.h"
#include "Model_FileSystem.h"
#include "Encoder_MP3.h"
//Qt includes
#include <QMessageBox>

View File

@ -21,57 +21,10 @@
#include "Encoder_Abstract.h"
#include <QStringList>
#include <QProcess>
#include <QMutex>
#include <QMutexLocker>
#include <QLibrary>
#include <Windows.h>
#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;
}

View File

@ -21,15 +21,14 @@
#pragma once
#include "Tool_Abstract.h"
#include "Model_AudioFile.h"
#include <QObject>
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;
};

View File

@ -27,11 +27,11 @@
#include <QProcess>
#include <QDir>
#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))

View File

@ -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);

View File

@ -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))
{

View File

@ -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);

38
src/Registry_Decoder.cpp Normal file
View File

@ -0,0 +1,38 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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 <QString>
#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;
}

31
src/Registry_Decoder.h Normal file
View File

@ -0,0 +1,31 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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);
};

View File

@ -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 <QUuid>
@ -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
////////////////////////////////////////////////////////////

View File

@ -23,6 +23,7 @@
#include <QThread>
#include <QUuid>
#include <QStringList>
#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;
};

167
src/Tool_Abstract.cpp Normal file
View File

@ -0,0 +1,167 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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 <QProcess>
#include <QMutex>
#include <QMutexLocker>
#include <QLibrary>
#include <Windows.h>
/*
* 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<const wchar_t*>(longPath.utf16()), NULL, NULL);
if(buffSize > 0)
{
wchar_t *buffer = new wchar_t[buffSize];
DWORD result = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), buffer, buffSize);
if(result > 0 && result < buffSize)
{
shortPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer));
}
delete[] buffer;
}
return (shortPath.isEmpty() ? longPath : shortPath);
}

48
src/Tool_Abstract.h Normal file
View File

@ -0,0 +1,48 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.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, 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 <QObject>
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;
};