2012-01-28 18:55:40 +01:00
///////////////////////////////////////////////////////////////////////////////
// Simple x264 Launcher
2014-01-27 19:58:24 +01:00
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
2012-01-28 18:55:40 +01:00
//
// 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 "thread_encode.h"
2012-01-29 19:14:46 +01:00
2012-01-28 19:59:04 +01:00
# include "global.h"
2012-01-29 19:14:46 +01:00
# include "model_options.h"
2013-07-03 21:34:21 +02:00
# include "model_preferences.h"
2014-02-14 00:01:00 +01:00
# include "model_sysinfo.h"
2013-11-03 18:34:20 +01:00
# include "job_object.h"
2014-02-14 00:01:00 +01:00
# include "binaries.h"
2012-01-29 19:14:46 +01:00
# include <QDate>
# include <QTime>
2012-01-31 00:13:32 +01:00
# include <QDateTime>
2012-01-30 04:58:42 +01:00
# include <QFileInfo>
# include <QDir>
2012-01-29 21:31:09 +01:00
# include <QProcess>
# include <QMutex>
2012-02-05 21:52:23 +01:00
# include <QTextCodec>
2012-02-27 21:39:15 +01:00
# include <QLocale>
2013-08-28 18:10:26 +02:00
# include <QCryptographicHash>
2012-01-29 21:31:09 +01:00
/*
* Static vars
*/
QMutex EncodeThread : : m_mutex_startProcess ;
2013-11-10 23:20:24 +01:00
/*
* RAII execution state handler
*/
2013-11-14 02:29:18 +01:00
class ExecutionStateHandler
2013-11-10 23:20:24 +01:00
{
public :
ExecutionStateHandler ( void )
{
x264_set_thread_execution_state ( true ) ;
}
~ ExecutionStateHandler ( void )
{
x264_set_thread_execution_state ( false ) ;
}
private :
//Disable copy constructor and assignment
ExecutionStateHandler ( const ExecutionStateHandler & other ) { }
ExecutionStateHandler & operator = ( const ExecutionStateHandler & ) { }
//Prevent object allocation on the heap
void * operator new ( size_t ) ; void * operator new [ ] ( size_t ) ;
void operator delete ( void * ) ; void operator delete [ ] ( void * ) ;
} ;
2012-01-30 17:50:19 +01:00
/*
* Macros
*/
2012-09-22 14:58:51 +02:00
# define CHECK_STATUS(ABORT_FLAG, OK_FLAG) do \
2012-01-30 17:50:19 +01:00
{ \
if ( ABORT_FLAG ) \
{ \
log ( " \n PROCESS ABORTED BY USER !!! " ) ; \
setStatus ( JobStatus_Aborted ) ; \
2012-02-04 01:12:21 +01:00
if ( QFileInfo ( indexFile ) . exists ( ) ) QFile : : remove ( indexFile ) ; \
2012-02-15 00:45:42 +01:00
if ( QFileInfo ( m_outputFileName ) . exists ( ) & & ( QFileInfo ( m_outputFileName ) . size ( ) = = 0 ) ) QFile : : remove ( m_outputFileName ) ; \
2012-01-30 17:50:19 +01:00
return ; \
} \
else if ( ! ( OK_FLAG ) ) \
{ \
setStatus ( JobStatus_Failed ) ; \
2012-02-04 01:12:21 +01:00
if ( QFileInfo ( indexFile ) . exists ( ) ) QFile : : remove ( indexFile ) ; \
2012-02-15 00:45:42 +01:00
if ( QFileInfo ( m_outputFileName ) . exists ( ) & & ( QFileInfo ( m_outputFileName ) . size ( ) = = 0 ) ) QFile : : remove ( m_outputFileName ) ; \
2012-01-30 17:50:19 +01:00
return ; \
} \
2012-09-22 14:58:51 +02:00
} \
while ( 0 )
2012-01-30 17:50:19 +01:00
2012-09-22 14:58:51 +02:00
# define APPEND_AND_CLEAR(LIST, STR) do \
2012-02-06 22:40:07 +01:00
{ \
if ( ! ( ( STR ) . isEmpty ( ) ) ) \
{ \
( LIST ) < < ( STR ) ; \
( STR ) . clear ( ) ; \
} \
2012-09-22 14:58:51 +02:00
} \
while ( 0 )
# define REMOVE_CUSTOM_ARG(LIST, ITER, FLAG, PARAM) do \
{ \
if ( ITER ! = LIST . end ( ) ) \
{ \
if ( ( * ITER ) . compare ( PARAM , Qt : : CaseInsensitive ) = = 0 ) \
{ \
log ( tr ( " WARNING: Custom parameter \" " PARAM " \" will be ignored in Pipe'd mode! \n " ) ) ; \
ITER = LIST . erase ( ITER ) ; \
if ( ITER ! = LIST . end ( ) ) \
{ \
if ( ! ( ( * ITER ) . startsWith ( " -- " , Qt : : CaseInsensitive ) ) ) ITER = LIST . erase ( ITER ) ; \
} \
FLAG = true ; \
} \
} \
} \
while ( 0 )
2012-02-06 22:40:07 +01:00
2012-01-30 17:50:19 +01:00
/*
* Static vars
*/
static const unsigned int REV_MULT = 10000 ;
2013-08-02 20:44:47 +02:00
static const char * VPS_TEST_FILE = " import vapoursynth as vs \n core = vs.get_core() \n v = core.std.BlankClip() \n v.set_output() \n " ;
2012-01-30 17:50:19 +01:00
2012-01-29 21:31:09 +01:00
///////////////////////////////////////////////////////////////////////////////
// Constructor & Destructor
///////////////////////////////////////////////////////////////////////////////
2014-02-14 00:01:00 +01:00
EncodeThread : : EncodeThread ( const QString & sourceFileName , const QString & outputFileName , const OptionsModel * options , const SysinfoModel * const sysinfo , const PreferencesModel * const preferences )
2012-01-28 18:55:40 +01:00
:
2012-01-29 15:57:23 +01:00
m_jobId ( QUuid : : createUuid ( ) ) ,
m_sourceFileName ( sourceFileName ) ,
2012-01-29 19:14:46 +01:00
m_outputFileName ( outputFileName ) ,
2012-01-29 21:31:09 +01:00
m_options ( new OptionsModel ( * options ) ) ,
2014-02-14 00:01:00 +01:00
m_sysinfo ( sysinfo ) ,
m_preferences ( preferences ) ,
2013-11-03 18:34:20 +01:00
m_jobObject ( new JobObject ) ,
2012-02-02 02:13:02 +01:00
m_semaphorePaused ( 0 )
2012-01-28 18:55:40 +01:00
{
2012-01-28 23:24:41 +01:00
m_abort = false ;
2012-02-02 02:13:02 +01:00
m_pause = false ;
2012-01-28 18:55:40 +01:00
}
EncodeThread : : ~ EncodeThread ( void )
{
2012-01-29 19:14:46 +01:00
X264_DELETE ( m_options ) ;
2013-11-03 18:34:20 +01:00
X264_DELETE ( m_jobObject ) ;
2012-01-28 18:55:40 +01:00
}
///////////////////////////////////////////////////////////////////////////////
// Thread entry point
///////////////////////////////////////////////////////////////////////////////
void EncodeThread : : run ( void )
{
2013-08-02 20:44:47 +02:00
# if !defined(_DEBUG)
2012-02-02 02:13:02 +01:00
__try
2012-01-28 19:59:04 +01:00
{
2012-02-02 02:13:02 +01:00
checkedRun ( ) ;
2012-01-28 19:59:04 +01:00
}
2012-02-02 02:13:02 +01:00
__except ( 1 )
2012-01-28 19:59:04 +01:00
{
2012-02-02 02:13:02 +01:00
qWarning ( " STRUCTURED EXCEPTION ERROR IN ENCODE THREAD !!! " ) ;
2012-01-28 19:59:04 +01:00
}
2013-08-02 20:44:47 +02:00
# else
checkedRun ( ) ;
# endif
2012-01-31 00:13:32 +01:00
2013-11-03 18:34:20 +01:00
if ( m_jobObject )
2012-01-31 00:13:32 +01:00
{
2013-11-03 18:34:20 +01:00
m_jobObject - > terminateJob ( 42 ) ;
X264_DELETE ( m_jobObject ) ;
2012-01-31 00:13:32 +01:00
}
2012-01-28 19:59:04 +01:00
}
2012-02-02 02:13:02 +01:00
void EncodeThread : : checkedRun ( void )
{
m_progress = 0 ;
m_status = JobStatus_Starting ;
try
{
try
{
2013-11-10 23:20:24 +01:00
ExecutionStateHandler executionStateHandler ;
2012-02-02 02:13:02 +01:00
encode ( ) ;
}
catch ( char * msg )
{
log ( tr ( " EXCEPTION ERROR IN THREAD: " ) . append ( QString : : fromLatin1 ( msg ) ) ) ;
setStatus ( JobStatus_Failed ) ;
}
catch ( . . . )
{
log ( tr ( " UNHANDLED EXCEPTION ERROR IN THREAD !!! " ) ) ;
setStatus ( JobStatus_Failed ) ;
}
}
catch ( . . . )
{
2013-11-03 18:34:20 +01:00
x264_fatal_exit ( L " Unhandeled exception error in encode thread! " ) ;
2012-02-02 02:13:02 +01:00
}
}
void EncodeThread : : start ( Priority priority )
{
qDebug ( " Thread starting... " ) ;
m_abort = false ;
m_pause = false ;
while ( m_semaphorePaused . tryAcquire ( 1 , 0 ) ) ;
QThread : : start ( priority ) ;
}
2012-01-29 21:31:09 +01:00
///////////////////////////////////////////////////////////////////////////////
// Encode functions
///////////////////////////////////////////////////////////////////////////////
2012-01-28 19:59:04 +01:00
void EncodeThread : : encode ( void )
{
2012-01-31 00:13:32 +01:00
QDateTime startTime = QDateTime : : currentDateTime ( ) ;
2012-02-02 02:13:02 +01:00
2012-01-29 19:14:46 +01:00
//Print some basic info
2012-04-30 19:26:41 +02:00
log ( tr ( " Simple x264 Launcher (Build #%1), built %2 \n " ) . arg ( QString : : number ( x264_version_build ( ) ) , x264_version_date ( ) . toString ( Qt : : ISODate ) ) ) ;
2012-01-29 19:14:46 +01:00
log ( tr ( " Job started at %1, %2. \n " ) . arg ( QDate : : currentDate ( ) . toString ( Qt : : ISODate ) , QTime : : currentTime ( ) . toString ( Qt : : ISODate ) ) ) ;
2013-05-11 21:52:07 +02:00
log ( tr ( " Source file: %1 " ) . arg ( QDir : : toNativeSeparators ( m_sourceFileName ) ) ) ;
log ( tr ( " Output file: %1 " ) . arg ( QDir : : toNativeSeparators ( m_outputFileName ) ) ) ;
2012-01-31 00:13:32 +01:00
2014-02-14 23:14:39 +01:00
//Print system info
log ( tr ( " \n --- SYSTEMINFO --- \n " ) ) ;
log ( tr ( " Binary Path: %1 " ) . arg ( QDir : : toNativeSeparators ( m_sysinfo - > getAppPath ( ) ) ) ) ;
log ( tr ( " Avisynth 2x: %1 " ) . arg ( m_sysinfo - > hasAVSSupport ( ) ? tr ( " YES " ) : tr ( " NO " ) ) ) ;
log ( tr ( " VapourSynth: %1 " ) . arg ( m_sysinfo - > hasVPSSupport ( ) ? QDir : : toNativeSeparators ( m_sysinfo - > getVPSPath ( ) ) : tr ( " N/A " ) ) ) ;
2013-08-07 15:34:02 +02:00
2012-01-31 00:13:32 +01:00
//Print encoder settings
log ( tr ( " \n --- SETTINGS --- \n " ) ) ;
2012-01-29 19:14:46 +01:00
log ( tr ( " RC Mode: %1 " ) . arg ( OptionsModel : : rcMode2String ( m_options - > rcMode ( ) ) ) ) ;
2012-01-31 00:13:32 +01:00
log ( tr ( " Preset: %1 " ) . arg ( m_options - > preset ( ) ) ) ;
log ( tr ( " Tuning: %1 " ) . arg ( m_options - > tune ( ) ) ) ;
2012-01-29 19:14:46 +01:00
log ( tr ( " Profile: %1 " ) . arg ( m_options - > profile ( ) ) ) ;
2014-02-10 21:33:04 +01:00
log ( tr ( " Custom: %1 " ) . arg ( m_options - > customEncParams ( ) . isEmpty ( ) ? tr ( " (None) " ) : m_options - > customEncParams ( ) ) ) ;
2012-01-29 21:31:09 +01:00
2012-01-30 04:58:42 +01:00
bool ok = false ;
2012-01-31 00:13:32 +01:00
unsigned int frames = 0 ;
2013-08-02 20:44:47 +02:00
//Seletct type of input
const int inputType = getInputType ( QFileInfo ( m_sourceFileName ) . suffix ( ) ) ;
2013-08-28 18:10:26 +02:00
const QString indexFile = QString ( " %1/x264_%2.ffindex " ) . arg ( QDir : : tempPath ( ) , stringToHash ( m_sourceFileName ) ) ;
2012-01-31 20:28:40 +01:00
//Checking x264 version
log ( tr ( " \n --- CHECK VERSION --- \n " ) ) ;
unsigned int revision_x264 = UINT_MAX ;
2012-02-02 04:00:05 +01:00
bool x264_modified = false ;
2014-02-14 00:01:00 +01:00
ok = ( ( revision_x264 = checkVersionX264 ( x264_modified ) ) ! = UINT_MAX ) ;
2012-01-31 20:28:40 +01:00
CHECK_STATUS ( m_abort , ok ) ;
//Checking avs2yuv version
unsigned int revision_avs2yuv = UINT_MAX ;
2013-08-02 20:44:47 +02:00
switch ( inputType )
2012-01-31 00:13:32 +01:00
{
2013-08-02 20:44:47 +02:00
case INPUT_AVISYN :
2014-02-14 23:14:39 +01:00
ok = ( ( revision_avs2yuv = checkVersionAvs2yuv ( ) ) ! = UINT_MAX ) ;
2012-01-31 00:13:32 +01:00
CHECK_STATUS ( m_abort , ok ) ;
2013-08-02 20:44:47 +02:00
break ;
case INPUT_VAPOUR :
2013-08-04 18:44:53 +02:00
ok = checkVersionVapoursynth ( ) ;
2013-08-02 20:44:47 +02:00
CHECK_STATUS ( m_abort , ok ) ;
break ;
2012-01-31 00:13:32 +01:00
}
2012-01-30 04:58:42 +01:00
2012-01-31 20:28:40 +01:00
//Print versions
2012-02-02 04:00:05 +01:00
log ( tr ( " \n x264 revision: %1 (core #%2) " ) . arg ( QString : : number ( revision_x264 % REV_MULT ) , QString : : number ( revision_x264 / REV_MULT ) ) . append ( x264_modified ? tr ( " - with custom patches! " ) : QString ( ) ) ) ;
2012-01-31 20:28:40 +01:00
if ( revision_avs2yuv ! = UINT_MAX ) log ( tr ( " Avs2YUV version: %1.%2.%3 " ) . arg ( QString : : number ( revision_avs2yuv / REV_MULT ) , QString : : number ( ( revision_avs2yuv % REV_MULT ) / 10 ) , QString : : number ( ( revision_avs2yuv % REV_MULT ) % 10 ) ) ) ;
2012-01-30 17:50:19 +01:00
2012-01-31 20:28:40 +01:00
//Is x264 revision supported?
2013-11-06 00:30:27 +01:00
if ( ( revision_x264 % REV_MULT ) < x264_version_x264_minimum_rev ( ) )
2012-01-30 17:50:19 +01:00
{
2013-11-06 00:30:27 +01:00
log ( tr ( " \n ERROR: Your revision of x264 is too old! (Minimum required revision is %2) " ) . arg ( QString : : number ( x264_version_x264_minimum_rev ( ) ) ) ) ;
2012-01-30 17:50:19 +01:00
setStatus ( JobStatus_Failed ) ;
return ;
}
2013-11-06 00:30:27 +01:00
if ( ( revision_x264 / REV_MULT ) ! = x264_version_x264_current_api ( ) )
2012-01-30 17:50:19 +01:00
{
log ( tr ( " \n WARNING: Your revision of x264 uses an unsupported core (API) version, take care! " ) ) ;
2013-11-06 00:30:27 +01:00
log ( tr ( " This application works best with x264 core (API) version %2. " ) . arg ( QString : : number ( x264_version_x264_current_api ( ) ) ) ) ;
2012-01-30 17:50:19 +01:00
}
2013-11-06 00:30:27 +01:00
if ( ( revision_avs2yuv ! = UINT_MAX ) & & ( ( revision_avs2yuv % REV_MULT ) ! = x264_version_x264_avs2yuv_ver ( ) ) )
2012-01-31 20:28:40 +01:00
{
2012-02-02 02:13:02 +01:00
log ( tr ( " \n ERROR: Your version of avs2yuv is unsupported (Required version: v0.24 BugMaster's mod 2) " ) ) ;
log ( tr ( " You can find the required version at: http://komisar.gin.by/tools/avs2yuv/ " ) ) ;
2012-01-31 20:28:40 +01:00
setStatus ( JobStatus_Failed ) ;
return ;
}
//Detect source info
2013-08-02 20:44:47 +02:00
if ( inputType ! = INPUT_NATIVE )
2012-01-31 20:28:40 +01:00
{
2013-08-02 20:44:47 +02:00
log ( tr ( " \n --- SOURCE INFO --- \n " ) ) ;
switch ( inputType )
{
case INPUT_AVISYN :
2014-02-14 23:14:39 +01:00
ok = checkPropertiesAVS ( frames ) ;
2013-08-02 20:44:47 +02:00
CHECK_STATUS ( m_abort , ok ) ;
break ;
case INPUT_VAPOUR :
2014-02-14 23:14:39 +01:00
ok = checkPropertiesVPS ( frames ) ;
2013-08-02 20:44:47 +02:00
CHECK_STATUS ( m_abort , ok ) ;
break ;
}
2012-01-31 20:28:40 +01:00
}
2012-01-30 04:58:42 +01:00
//Run encoding passes
if ( m_options - > rcMode ( ) = = OptionsModel : : RCMode_2Pass )
{
QFileInfo info ( m_outputFileName ) ;
QString passLogFile = QString ( " %1/%2.stats " ) . arg ( info . path ( ) , info . completeBaseName ( ) ) ;
if ( QFileInfo ( passLogFile ) . exists ( ) )
{
int n = 2 ;
while ( QFileInfo ( passLogFile ) . exists ( ) )
{
passLogFile = QString ( " %1/%2.%3.stats " ) . arg ( info . path ( ) , info . completeBaseName ( ) , QString : : number ( n + + ) ) ;
}
}
2012-01-30 17:50:19 +01:00
log ( tr ( " \n --- PASS 1 --- \n " ) ) ;
2014-02-14 23:14:39 +01:00
ok = runEncodingPass ( inputType , frames , indexFile , 1 , passLogFile ) ;
2012-01-30 17:50:19 +01:00
CHECK_STATUS ( m_abort , ok ) ;
2012-01-30 04:58:42 +01:00
2012-01-30 17:50:19 +01:00
log ( tr ( " \n --- PASS 2 --- \n " ) ) ;
2014-02-14 23:14:39 +01:00
ok = runEncodingPass ( inputType , frames , indexFile , 2 , passLogFile ) ;
2012-01-30 17:50:19 +01:00
CHECK_STATUS ( m_abort , ok ) ;
2012-01-30 04:58:42 +01:00
}
else
{
2012-01-30 17:50:19 +01:00
log ( tr ( " \n --- ENCODING --- \n " ) ) ;
2014-02-14 23:14:39 +01:00
ok = runEncodingPass ( inputType , frames , indexFile ) ;
2012-01-30 17:50:19 +01:00
CHECK_STATUS ( m_abort , ok ) ;
2012-01-30 04:58:42 +01:00
}
2012-01-30 17:50:19 +01:00
log ( tr ( " \n --- DONE --- \n " ) ) ;
2012-01-31 00:13:32 +01:00
int timePassed = startTime . secsTo ( QDateTime : : currentDateTime ( ) ) ;
2013-11-03 16:56:55 +01:00
log ( tr ( " Job finished at %1, %2. Process took %3 minutes, %4 seconds. " ) . arg ( QDate : : currentDate ( ) . toString ( Qt : : ISODate ) , QTime : : currentTime ( ) . toString ( Qt : : ISODate ) , QString : : number ( timePassed / 60 ) , QString : : number ( timePassed % 60 ) ) ) ;
2012-01-30 04:58:42 +01:00
setStatus ( JobStatus_Completed ) ;
}
2013-10-13 22:09:05 +02:00
# define X264_UPDATE_PROGRESS(X) do \
{ \
bool ok = false ; \
unsigned int progress = ( X ) . cap ( 1 ) . toUInt ( & ok ) ; \
setStatus ( ( pass = = 2 ) ? JobStatus_Running_Pass2 : ( ( pass = = 1 ) ? JobStatus_Running_Pass1 : JobStatus_Running ) ) ; \
if ( ok & & ( ( progress > last_progress ) | | ( last_progress = = UINT_MAX ) ) ) \
{ \
setProgress ( progress ) ; \
size_estimate = estimateSize ( progress ) ; \
last_progress = progress ; \
} \
setDetails ( tr ( " %1, est. file size %2 " ) . arg ( text . mid ( offset ) . trimmed ( ) , sizeToString ( size_estimate ) ) ) ; \
last_indexing = UINT_MAX ; \
} \
while ( 0 )
2014-02-14 23:14:39 +01:00
bool EncodeThread : : runEncodingPass ( const int & inputType , const unsigned int & frames , const QString & indexFile , const int & pass , const QString & passLogFile )
2012-01-30 04:58:42 +01:00
{
2013-08-02 20:44:47 +02:00
QProcess processEncode , processInput ;
2012-01-31 15:15:15 +01:00
2013-08-02 20:44:47 +02:00
if ( inputType ! = INPUT_NATIVE )
2012-01-31 00:13:32 +01:00
{
2013-08-02 20:44:47 +02:00
QStringList cmdLine_Input ;
processInput . setStandardOutputProcess ( & processEncode ) ;
switch ( inputType )
2012-02-12 15:58:28 +01:00
{
2013-08-02 20:44:47 +02:00
case INPUT_AVISYN :
if ( ! m_options - > customAvs2YUV ( ) . isEmpty ( ) )
{
cmdLine_Input . append ( splitParams ( m_options - > customAvs2YUV ( ) ) ) ;
}
2013-11-08 14:15:40 +01:00
cmdLine_Input < < QDir : : toNativeSeparators ( x264_path2ansi ( m_sourceFileName , true ) ) ;
2013-08-02 20:44:47 +02:00
cmdLine_Input < < " - " ;
log ( " Creating Avisynth process: " ) ;
2014-02-14 23:14:39 +01:00
if ( ! startProcess ( processInput , AVS_BINARY ( m_sysinfo , m_preferences ) , cmdLine_Input , false ) )
2013-08-02 20:44:47 +02:00
{
return false ;
}
break ;
case INPUT_VAPOUR :
2013-11-08 14:15:40 +01:00
cmdLine_Input < < QDir : : toNativeSeparators ( x264_path2ansi ( m_sourceFileName , true ) ) ;
2013-08-02 20:44:47 +02:00
cmdLine_Input < < " - " < < " -y4m " ;
log ( " Creating Vapoursynth process: " ) ;
2014-02-14 23:14:39 +01:00
if ( ! startProcess ( processInput , VPS_BINARY ( m_sysinfo , m_preferences ) , cmdLine_Input , false ) )
2013-08-02 20:44:47 +02:00
{
return false ;
}
break ;
default :
throw " Bad input type encontered! " ;
2012-01-31 15:15:15 +01:00
}
2012-01-31 00:13:32 +01:00
}
2014-02-14 23:14:39 +01:00
QStringList cmdLine_Encode = buildCommandLine ( ( inputType ! = INPUT_NATIVE ) , frames , indexFile , pass , passLogFile ) ;
2012-01-29 19:14:46 +01:00
2012-01-31 15:15:15 +01:00
log ( " Creating x264 process: " ) ;
2014-02-14 23:14:39 +01:00
if ( ! startProcess ( processEncode , ENC_BINARY ( m_sysinfo , m_options ) , cmdLine_Encode ) )
2012-01-28 19:59:04 +01:00
{
2012-01-31 15:15:15 +01:00
return false ;
2012-01-29 21:31:09 +01:00
}
2012-02-27 21:39:15 +01:00
QRegExp regExpIndexing ( " indexing.+ \\ [( \\ d+) \ \ . ( \ \ d + ) % \ \ ] " ) ;
2012-02-23 03:18:46 +01:00
QRegExp regExpProgress ( " \\ [( \\ d+) \ \ . ( \ \ d + ) % \ \ ] . + frames " ) ;
2013-10-13 22:09:05 +02:00
QRegExp regExpModified ( " \\ [ \\ s*( \\ d+) \ \ . ( \ \ d + ) % \ \ ] \ \ s + ( \ \ d + ) / ( \ \ d + ) \ \ s ( \ \ d + ) . ( \ \ d + ) \ \ s ( \ \ d + ) . ( \ \ d + ) \ \ s + ( \ \ d + ) : ( \ \ d + ) : ( \ \ d + ) \ \ s + ( \ \ d + ) : ( \ \ d + ) : ( \ \ d + ) " ) ;
2012-01-31 00:13:32 +01:00
QRegExp regExpFrameCnt ( " ^( \\ d+) frames : " ) ;
2012-01-28 23:24:41 +01:00
2012-02-05 21:52:23 +01:00
QTextCodec * localCodec = QTextCodec : : codecForName ( " System " ) ;
2012-01-29 21:31:09 +01:00
bool bTimeout = false ;
bool bAborted = false ;
2012-01-28 23:24:41 +01:00
2012-02-27 21:39:15 +01:00
unsigned int last_progress = UINT_MAX ;
unsigned int last_indexing = UINT_MAX ;
qint64 size_estimate = 0 I64 ;
2012-02-02 02:13:02 +01:00
//Main processing loop
2012-01-31 15:15:15 +01:00
while ( processEncode . state ( ) ! = QProcess : : NotRunning )
2012-01-29 21:31:09 +01:00
{
2012-02-02 02:13:02 +01:00
unsigned int waitCounter = 0 ;
//Wait until new output is available
forever
2012-01-29 21:31:09 +01:00
{
2012-02-02 02:13:02 +01:00
if ( m_abort )
2012-01-30 04:58:42 +01:00
{
2012-01-31 15:15:15 +01:00
processEncode . kill ( ) ;
2013-08-02 20:44:47 +02:00
processInput . kill ( ) ;
2012-02-02 02:13:02 +01:00
bAborted = true ;
2012-01-30 04:58:42 +01:00
break ;
}
2012-02-02 02:13:02 +01:00
if ( m_pause & & ( processEncode . state ( ) = = QProcess : : Running ) )
{
JobStatus previousStatus = m_status ;
setStatus ( JobStatus_Paused ) ;
log ( tr ( " Job paused by user at %1, %2. " ) . arg ( QDate : : currentDate ( ) . toString ( Qt : : ISODate ) , QTime : : currentTime ( ) . toString ( Qt : : ISODate ) ) ) ;
bool ok [ 2 ] = { false , false } ;
2013-11-03 18:34:20 +01:00
QProcess * proc [ 2 ] = { & processEncode , & processInput } ;
ok [ 0 ] = x264_suspendProcess ( proc [ 0 ] , true ) ;
ok [ 1 ] = x264_suspendProcess ( proc [ 1 ] , true ) ;
2012-11-28 23:36:00 +01:00
while ( m_pause ) m_semaphorePaused . tryAcquire ( 1 , 5000 ) ;
2012-02-02 02:13:02 +01:00
while ( m_semaphorePaused . tryAcquire ( 1 , 0 ) ) ;
2013-11-03 18:34:20 +01:00
ok [ 0 ] = x264_suspendProcess ( proc [ 0 ] , false ) ;
ok [ 1 ] = x264_suspendProcess ( proc [ 1 ] , false ) ;
2012-02-02 02:13:02 +01:00
if ( ! m_abort ) setStatus ( previousStatus ) ;
log ( tr ( " Job resumed by user at %1, %2. " ) . arg ( QDate : : currentDate ( ) . toString ( Qt : : ISODate ) , QTime : : currentTime ( ) . toString ( Qt : : ISODate ) ) ) ;
waitCounter = 0 ;
continue ;
}
2012-02-11 16:10:21 +01:00
if ( ! processEncode . waitForReadyRead ( m_processTimeoutInterval ) )
2012-02-02 02:13:02 +01:00
{
if ( processEncode . state ( ) = = QProcess : : Running )
{
2013-08-04 18:44:53 +02:00
if ( + + waitCounter > m_processTimeoutMaxCounter )
2012-02-02 02:13:02 +01:00
{
2014-02-14 23:14:39 +01:00
if ( m_preferences - > getAbortOnTimeout ( ) )
2013-08-04 18:44:53 +02:00
{
processEncode . kill ( ) ;
qWarning ( " x264 process timed out <-- killing! " ) ;
log ( " \n PROCESS TIMEOUT !!! " ) ;
bTimeout = true ;
break ;
}
2012-02-02 02:13:02 +01:00
}
2012-02-11 16:10:21 +01:00
else if ( waitCounter = = m_processTimeoutWarning )
{
unsigned int timeOut = ( waitCounter * m_processTimeoutInterval ) / 1000U ;
log ( tr ( " Warning: x264 did not respond for %1 seconds, potential deadlock... " ) . arg ( QString : : number ( timeOut ) ) ) ;
}
2012-02-02 02:13:02 +01:00
continue ;
}
}
if ( m_abort | | ( m_pause & & ( processEncode . state ( ) = = QProcess : : Running ) ) )
{
continue ;
}
break ;
}
//Exit main processing loop now?
if ( bAborted | | bTimeout )
{
break ;
2012-01-28 23:24:41 +01:00
}
2012-02-02 02:13:02 +01:00
//Process all output
2012-01-31 15:15:15 +01:00
while ( processEncode . bytesAvailable ( ) > 0 )
2012-01-29 21:31:09 +01:00
{
2012-01-31 15:15:15 +01:00
QList < QByteArray > lines = processEncode . readLine ( ) . split ( ' \r ' ) ;
2012-01-30 04:58:42 +01:00
while ( ! lines . isEmpty ( ) )
2012-01-29 21:31:09 +01:00
{
2012-02-05 21:52:23 +01:00
QString text = localCodec - > toUnicode ( lines . takeFirst ( ) . constData ( ) ) . simplified ( ) ;
2012-01-30 04:58:42 +01:00
int offset = - 1 ;
if ( ( offset = regExpProgress . lastIndexIn ( text ) ) > = 0 )
2012-01-29 21:31:09 +01:00
{
2013-10-13 22:09:05 +02:00
X264_UPDATE_PROGRESS ( regExpProgress ) ;
2012-01-30 04:58:42 +01:00
}
else if ( ( offset = regExpIndexing . lastIndexIn ( text ) ) > = 0 )
{
bool ok = false ;
unsigned int progress = regExpIndexing . cap ( 1 ) . toUInt ( & ok ) ;
setStatus ( JobStatus_Indexing ) ;
2012-02-27 21:39:15 +01:00
if ( ok & & ( ( progress > last_indexing ) | | ( last_indexing = = UINT_MAX ) ) )
{
setProgress ( progress ) ;
last_indexing = progress ;
}
2012-01-30 04:58:42 +01:00
setDetails ( text . mid ( offset ) . trimmed ( ) ) ;
2012-02-27 21:39:15 +01:00
last_progress = UINT_MAX ;
2012-01-30 04:58:42 +01:00
}
2012-01-31 00:13:32 +01:00
else if ( ( offset = regExpFrameCnt . lastIndexIn ( text ) ) > = 0 )
{
2012-02-27 21:39:15 +01:00
last_progress = last_indexing = UINT_MAX ;
2012-01-31 00:13:32 +01:00
setStatus ( ( pass = = 2 ) ? JobStatus_Running_Pass2 : ( ( pass = = 1 ) ? JobStatus_Running_Pass1 : JobStatus_Running ) ) ;
setDetails ( text . mid ( offset ) . trimmed ( ) ) ;
}
2013-10-13 22:09:05 +02:00
else if ( ( offset = regExpModified . lastIndexIn ( text ) ) > = 0 )
{
X264_UPDATE_PROGRESS ( regExpModified ) ;
}
2012-01-30 04:58:42 +01:00
else if ( ! text . isEmpty ( ) )
{
2012-02-27 21:39:15 +01:00
last_progress = last_indexing = UINT_MAX ;
2012-01-30 04:58:42 +01:00
log ( text ) ;
2012-01-29 21:31:09 +01:00
}
}
}
}
2012-01-31 15:15:15 +01:00
processEncode . waitForFinished ( 5000 ) ;
if ( processEncode . state ( ) ! = QProcess : : NotRunning )
2012-01-29 21:31:09 +01:00
{
2012-01-31 15:15:15 +01:00
qWarning ( " x264 process still running, going to kill it! " ) ;
processEncode . kill ( ) ;
processEncode . waitForFinished ( - 1 ) ;
}
2013-08-02 20:44:47 +02:00
processInput . waitForFinished ( 5000 ) ;
if ( processInput . state ( ) ! = QProcess : : NotRunning )
2012-01-31 15:15:15 +01:00
{
2013-08-02 20:44:47 +02:00
qWarning ( " Input process still running, going to kill it! " ) ;
processInput . kill ( ) ;
processInput . waitForFinished ( - 1 ) ;
2012-01-29 21:31:09 +01:00
}
2012-02-02 02:13:02 +01:00
if ( ! ( bTimeout | | bAborted ) )
2012-01-31 15:15:15 +01:00
{
2013-08-02 20:44:47 +02:00
while ( processInput . bytesAvailable ( ) > 0 )
2012-02-02 02:13:02 +01:00
{
2013-08-02 20:44:47 +02:00
switch ( inputType )
{
case INPUT_AVISYN :
log ( tr ( " av2y [info]: %1 " ) . arg ( QString : : fromUtf8 ( processInput . readLine ( ) ) . simplified ( ) ) ) ;
break ;
case INPUT_VAPOUR :
log ( tr ( " vpyp [info]: %1 " ) . arg ( QString : : fromUtf8 ( processInput . readLine ( ) ) . simplified ( ) ) ) ;
break ;
}
2012-02-02 02:13:02 +01:00
}
2012-01-31 15:15:15 +01:00
}
2013-08-02 20:44:47 +02:00
if ( ( inputType ! = INPUT_NATIVE ) & & ( processInput . exitCode ( ) ! = EXIT_SUCCESS ) )
2012-01-29 21:31:09 +01:00
{
2012-01-31 00:13:32 +01:00
if ( ! ( bTimeout | | bAborted ) )
{
2013-11-10 18:32:37 +01:00
const int exitCode = processInput . exitCode ( ) ;
log ( tr ( " \n WARNING: Input process exited with error (code: %1), your encode might be *incomplete* !!! " ) . arg ( QString : : number ( exitCode ) ) ) ;
2013-11-29 20:27:45 +01:00
if ( ( inputType = = INPUT_AVISYN ) & & ( ( exitCode < 0 ) | | ( exitCode > = 32 ) ) )
2013-11-10 18:32:37 +01:00
{
log ( tr ( " \n IMPORTANT: The Avs2YUV process terminated abnormally. This means Avisynth or one of your Avisynth-Plugin's just crashed. " ) ) ;
log ( tr ( " IMPORTANT: Please fix your Avisynth script and try again! If you use Avisynth-MT, try using a *stable* Avisynth instead! " ) ) ;
}
2013-11-29 20:27:45 +01:00
if ( ( inputType = = INPUT_VAPOUR ) & & ( ( exitCode < 0 ) | | ( exitCode > = 32 ) ) )
2013-11-10 18:32:37 +01:00
{
log ( tr ( " \n IMPORTANT: The Vapoursynth process terminated abnormally. This means Vapoursynth or one of your Vapoursynth-Plugin's just crashed. " ) ) ;
}
2012-01-31 15:15:15 +01:00
}
}
if ( bTimeout | | bAborted | | processEncode . exitCode ( ) ! = EXIT_SUCCESS )
{
if ( ! ( bTimeout | | bAborted ) )
{
log ( tr ( " \n PROCESS EXITED WITH ERROR CODE: %1 " ) . arg ( QString : : number ( processEncode . exitCode ( ) ) ) ) ;
2012-01-31 00:13:32 +01:00
}
2012-01-31 15:15:15 +01:00
processEncode . close ( ) ;
2013-08-02 20:44:47 +02:00
processInput . close ( ) ;
2012-01-30 04:58:42 +01:00
return false ;
2012-01-29 21:31:09 +01:00
}
2012-01-31 15:15:15 +01:00
2012-02-27 21:39:15 +01:00
QThread : : yieldCurrentThread ( ) ;
const qint64 finalSize = QFileInfo ( m_outputFileName ) . size ( ) ;
QLocale locale ( QLocale : : English ) ;
log ( tr ( " Final file size is %1 bytes. " ) . arg ( locale . toString ( finalSize ) ) ) ;
2012-01-31 15:51:13 +01:00
switch ( pass )
{
case 1 :
setStatus ( JobStatus_Running_Pass1 ) ;
setDetails ( tr ( " First pass completed. Preparing for second pass... " ) ) ;
break ;
case 2 :
setStatus ( JobStatus_Running_Pass2 ) ;
2012-02-27 21:39:15 +01:00
setDetails ( tr ( " Second pass completed successfully. Final size is %1. " ) . arg ( sizeToString ( finalSize ) ) ) ;
2012-01-31 15:51:13 +01:00
break ;
default :
setStatus ( JobStatus_Running ) ;
2012-02-27 21:39:15 +01:00
setDetails ( tr ( " Encode completed successfully. Final size is %1. " ) . arg ( sizeToString ( finalSize ) ) ) ;
2012-01-31 15:51:13 +01:00
break ;
}
2012-01-30 04:58:42 +01:00
setProgress ( 100 ) ;
2012-01-31 15:15:15 +01:00
processEncode . close ( ) ;
2013-08-02 20:44:47 +02:00
processInput . close ( ) ;
2012-01-30 04:58:42 +01:00
return true ;
2012-01-29 21:31:09 +01:00
}
2014-02-14 23:14:39 +01:00
QStringList EncodeThread : : buildCommandLine ( const bool & usePipe , const unsigned int & frames , const QString & indexFile , const int & pass , const QString & passLogFile )
2012-01-29 21:31:09 +01:00
{
QStringList cmdLine ;
2012-02-04 15:56:38 +01:00
double crf_int = 0.0 , crf_frc = 0.0 ;
2012-01-29 21:31:09 +01:00
2012-01-30 04:58:42 +01:00
switch ( m_options - > rcMode ( ) )
{
case OptionsModel : : RCMode_CQ :
2012-02-04 15:56:38 +01:00
cmdLine < < " --qp " < < QString : : number ( qRound ( m_options - > quantizer ( ) ) ) ;
break ;
case OptionsModel : : RCMode_CRF :
crf_frc = modf ( m_options - > quantizer ( ) , & crf_int ) ;
cmdLine < < " --crf " < < QString ( " %1.%2 " ) . arg ( QString : : number ( qRound ( crf_int ) ) , QString : : number ( qRound ( crf_frc * 10.0 ) ) ) ;
2012-01-30 04:58:42 +01:00
break ;
case OptionsModel : : RCMode_2Pass :
case OptionsModel : : RCMode_ABR :
cmdLine < < " --bitrate " < < QString : : number ( m_options - > bitrate ( ) ) ;
break ;
default :
throw " Bad rate-control mode !!! " ;
break ;
}
2012-01-29 21:31:09 +01:00
2012-01-30 04:58:42 +01:00
if ( ( pass = = 1 ) | | ( pass = = 2 ) )
{
cmdLine < < " --pass " < < QString : : number ( pass ) ;
2013-08-28 18:10:26 +02:00
cmdLine < < " --stats " < < QDir : : toNativeSeparators ( passLogFile ) ;
2012-01-30 04:58:42 +01:00
}
2012-02-02 02:13:02 +01:00
cmdLine < < " --preset " < < m_options - > preset ( ) . toLower ( ) ;
2012-01-29 21:31:09 +01:00
if ( m_options - > tune ( ) . compare ( " none " , Qt : : CaseInsensitive ) )
{
cmdLine < < " --tune " < < m_options - > tune ( ) . toLower ( ) ;
2012-01-28 19:59:04 +01:00
}
2012-02-02 02:13:02 +01:00
2014-02-14 23:14:39 +01:00
if ( m_options - > profile ( ) . compare ( " auto " , Qt : : CaseInsensitive ) ! = 0 )
2012-02-02 02:13:02 +01:00
{
2014-02-14 23:14:39 +01:00
if ( ( m_options - > encType ( ) = = OptionsModel : : EncType_X264 ) & & ( m_options - > encVariant ( ) = = OptionsModel : : EncVariant_LoBit ) )
2012-03-25 22:11:07 +02:00
{
cmdLine < < " --profile " < < m_options - > profile ( ) . toLower ( ) ;
}
2012-02-02 02:13:02 +01:00
}
2012-01-30 04:58:42 +01:00
2014-02-10 21:33:04 +01:00
if ( ! m_options - > customEncParams ( ) . isEmpty ( ) )
2012-01-30 04:58:42 +01:00
{
2014-02-10 21:33:04 +01:00
QStringList customArgs = splitParams ( m_options - > customEncParams ( ) ) ;
2012-09-22 14:58:51 +02:00
if ( usePipe )
{
QStringList : : iterator i = customArgs . begin ( ) ;
while ( i ! = customArgs . end ( ) )
{
bool bModified = false ;
REMOVE_CUSTOM_ARG ( customArgs , i , bModified , " --fps " ) ;
REMOVE_CUSTOM_ARG ( customArgs , i , bModified , " --frames " ) ;
if ( ! bModified ) i + + ;
}
}
cmdLine . append ( customArgs ) ;
2012-01-30 04:58:42 +01:00
}
2013-08-28 18:10:26 +02:00
cmdLine < < " --output " < < QDir : : toNativeSeparators ( m_outputFileName ) ;
2012-01-31 00:13:32 +01:00
if ( usePipe )
{
2012-01-31 15:15:15 +01:00
if ( frames < 1 ) throw " Frames not set! " ;
2012-01-31 00:13:32 +01:00
cmdLine < < " --frames " < < QString : : number ( frames ) ;
cmdLine < < " --demuxer " < < " y4m " ;
cmdLine < < " --stdin " < < " y4m " < < " - " ;
}
else
{
2013-08-28 18:10:26 +02:00
cmdLine < < " --index " < < QDir : : toNativeSeparators ( indexFile ) ;
cmdLine < < QDir : : toNativeSeparators ( m_sourceFileName ) ;
2012-01-31 00:13:32 +01:00
}
2012-01-28 19:59:04 +01:00
2012-01-29 21:31:09 +01:00
return cmdLine ;
}
2012-01-28 19:59:04 +01:00
2014-02-14 00:01:00 +01:00
unsigned int EncodeThread : : checkVersionX264 ( bool & modified )
2012-01-30 17:50:19 +01:00
{
2014-02-14 23:14:39 +01:00
if ( m_preferences - > getSkipVersionTest ( ) )
2013-07-07 16:11:47 +02:00
{
log ( " Warning: Skipping x264 version check this time! " ) ;
return ( 999 * REV_MULT ) + ( 9999 % REV_MULT ) ;
}
2012-01-30 17:50:19 +01:00
QProcess process ;
QStringList cmdLine = QStringList ( ) < < " --version " ;
log ( " Creating process: " ) ;
2014-02-14 00:01:00 +01:00
if ( ! startProcess ( process , ENC_BINARY ( m_sysinfo , m_options ) , cmdLine ) )
2012-01-30 17:50:19 +01:00
{
return false ; ;
}
2012-02-02 04:00:05 +01:00
QRegExp regExpVersion ( " \\ bx264 \\ s( \\ d) \ \ . ( \ \ d + ) \ \ . ( \ \ d + ) \ \ s ( [ a - f0 - 9 ] { 7 } ) " , Qt::CaseInsensitive);
QRegExp regExpVersionMod ( " \\ bx264 ( \\ d) \ \ . ( \ \ d + ) \ \ . ( \ \ d + ) " , Qt::CaseInsensitive) ;
2012-01-30 17:50:19 +01:00
bool bTimeout = false ;
bool bAborted = false ;
unsigned int revision = UINT_MAX ;
unsigned int coreVers = UINT_MAX ;
2012-02-02 04:00:05 +01:00
modified = false ;
2012-01-30 17:50:19 +01:00
while ( process . state ( ) ! = QProcess : : NotRunning )
{
if ( m_abort )
{
process . kill ( ) ;
bAborted = true ;
break ;
}
2012-02-02 02:13:02 +01:00
if ( ! process . waitForReadyRead ( ) )
2012-01-30 17:50:19 +01:00
{
if ( process . state ( ) = = QProcess : : Running )
{
process . kill ( ) ;
qWarning ( " x264 process timed out <-- killing! " ) ;
log ( " \n PROCESS TIMEOUT !!! " ) ;
bTimeout = true ;
break ;
}
}
while ( process . bytesAvailable ( ) > 0 )
{
QList < QByteArray > lines = process . readLine ( ) . split ( ' \r ' ) ;
while ( ! lines . isEmpty ( ) )
{
QString text = QString : : fromUtf8 ( lines . takeFirst ( ) . constData ( ) ) . simplified ( ) ;
int offset = - 1 ;
if ( ( offset = regExpVersion . lastIndexIn ( text ) ) > = 0 )
{
bool ok1 = false , ok2 = false ;
unsigned int temp1 = regExpVersion . cap ( 2 ) . toUInt ( & ok1 ) ;
unsigned int temp2 = regExpVersion . cap ( 3 ) . toUInt ( & ok2 ) ;
if ( ok1 ) coreVers = temp1 ;
if ( ok2 ) revision = temp2 ;
}
2012-02-02 04:00:05 +01:00
else if ( ( offset = regExpVersionMod . lastIndexIn ( text ) ) > = 0 )
{
bool ok1 = false , ok2 = false ;
unsigned int temp1 = regExpVersionMod . cap ( 2 ) . toUInt ( & ok1 ) ;
unsigned int temp2 = regExpVersionMod . cap ( 3 ) . toUInt ( & ok2 ) ;
if ( ok1 ) coreVers = temp1 ;
if ( ok2 ) revision = temp2 ;
modified = true ;
}
2012-01-30 17:50:19 +01:00
if ( ! text . isEmpty ( ) )
{
log ( text ) ;
}
}
}
}
process . waitForFinished ( ) ;
if ( process . state ( ) ! = QProcess : : NotRunning )
{
process . kill ( ) ;
process . waitForFinished ( - 1 ) ;
}
if ( bTimeout | | bAborted | | process . exitCode ( ) ! = EXIT_SUCCESS )
{
2012-01-31 00:13:32 +01:00
if ( ! ( bTimeout | | bAborted ) )
{
log ( tr ( " \n PROCESS EXITED WITH ERROR CODE: %1 " ) . arg ( QString : : number ( process . exitCode ( ) ) ) ) ;
}
2012-01-30 17:50:19 +01:00
return UINT_MAX ;
}
if ( ( revision = = UINT_MAX ) | | ( coreVers = = UINT_MAX ) )
{
log ( tr ( " \n FAILED TO DETERMINE X264 VERSION !!! " ) ) ;
return UINT_MAX ;
}
2012-01-31 20:28:40 +01:00
return ( coreVers * REV_MULT ) + ( revision % REV_MULT ) ;
}
2014-02-14 23:14:39 +01:00
unsigned int EncodeThread : : checkVersionAvs2yuv ( void )
2012-01-31 20:28:40 +01:00
{
2014-02-14 23:14:39 +01:00
if ( ! m_sysinfo - > hasAVSSupport ( ) )
{
log ( tr ( " \n AVS INPUT REQUIRES VAPOURSYNTH, BUT IT IS *NOT* AVAILABLE !!! " ) ) ;
return false ;
}
2012-01-31 20:28:40 +01:00
QProcess process ;
log ( " \n Creating process: " ) ;
2014-02-14 23:14:39 +01:00
if ( ! startProcess ( process , AVS_BINARY ( m_sysinfo , m_preferences ) , QStringList ( ) ) )
2012-01-31 20:28:40 +01:00
{
return false ; ;
}
2012-02-02 04:00:05 +01:00
QRegExp regExpVersionMod ( " \\ bAvs2YUV ( \\ d+) . ( \ \ d + ) bm ( \ \ d ) \ \ b " , Qt::CaseInsensitive) ;
QRegExp regExpVersionOld ( " \\ bAvs2YUV ( \\ d+) . ( \ \ d + ) \ \ b " , Qt::CaseInsensitive) ;
2012-01-31 20:28:40 +01:00
bool bTimeout = false ;
bool bAborted = false ;
unsigned int ver_maj = UINT_MAX ;
unsigned int ver_min = UINT_MAX ;
2012-02-02 02:13:02 +01:00
unsigned int ver_mod = 0 ;
2012-01-31 20:28:40 +01:00
while ( process . state ( ) ! = QProcess : : NotRunning )
{
if ( m_abort )
{
process . kill ( ) ;
bAborted = true ;
break ;
}
2012-02-02 02:13:02 +01:00
if ( ! process . waitForReadyRead ( ) )
2012-01-31 20:28:40 +01:00
{
if ( process . state ( ) = = QProcess : : Running )
{
process . kill ( ) ;
qWarning ( " Avs2YUV process timed out <-- killing! " ) ;
log ( " \n PROCESS TIMEOUT !!! " ) ;
bTimeout = true ;
break ;
}
}
while ( process . bytesAvailable ( ) > 0 )
{
QList < QByteArray > lines = process . readLine ( ) . split ( ' \r ' ) ;
while ( ! lines . isEmpty ( ) )
{
QString text = QString : : fromUtf8 ( lines . takeFirst ( ) . constData ( ) ) . simplified ( ) ;
int offset = - 1 ;
2012-02-02 02:13:02 +01:00
if ( ( ver_maj = = UINT_MAX ) | | ( ver_min = = UINT_MAX ) | | ( ver_mod = = UINT_MAX ) )
2012-01-31 20:28:40 +01:00
{
if ( ! text . isEmpty ( ) )
{
log ( text ) ;
}
}
2012-02-02 02:13:02 +01:00
if ( ( offset = regExpVersionMod . lastIndexIn ( text ) ) > = 0 )
2012-01-31 20:28:40 +01:00
{
bool ok1 = false , ok2 = false , ok3 = false ;
2012-02-02 02:13:02 +01:00
unsigned int temp1 = regExpVersionMod . cap ( 1 ) . toUInt ( & ok1 ) ;
unsigned int temp2 = regExpVersionMod . cap ( 2 ) . toUInt ( & ok2 ) ;
unsigned int temp3 = regExpVersionMod . cap ( 3 ) . toUInt ( & ok3 ) ;
if ( ok1 ) ver_maj = temp1 ;
if ( ok2 ) ver_min = temp2 ;
if ( ok3 ) ver_mod = temp3 ;
}
else if ( ( offset = regExpVersionOld . lastIndexIn ( text ) ) > = 0 )
{
bool ok1 = false , ok2 = false ;
unsigned int temp1 = regExpVersionOld . cap ( 1 ) . toUInt ( & ok1 ) ;
unsigned int temp2 = regExpVersionOld . cap ( 2 ) . toUInt ( & ok2 ) ;
2012-01-31 20:28:40 +01:00
if ( ok1 ) ver_maj = temp1 ;
if ( ok2 ) ver_min = temp2 ;
}
}
}
}
process . waitForFinished ( ) ;
if ( process . state ( ) ! = QProcess : : NotRunning )
{
process . kill ( ) ;
process . waitForFinished ( - 1 ) ;
}
if ( bTimeout | | bAborted | | ( ( process . exitCode ( ) ! = EXIT_SUCCESS ) & & ( process . exitCode ( ) ! = 2 ) ) )
{
if ( ! ( bTimeout | | bAborted ) )
{
log ( tr ( " \n PROCESS EXITED WITH ERROR CODE: %1 " ) . arg ( QString : : number ( process . exitCode ( ) ) ) ) ;
}
return UINT_MAX ;
}
2012-02-02 02:13:02 +01:00
if ( ( ver_maj = = UINT_MAX ) | | ( ver_min = = UINT_MAX ) )
2012-01-31 20:28:40 +01:00
{
log ( tr ( " \n FAILED TO DETERMINE AVS2YUV VERSION !!! " ) ) ;
return UINT_MAX ;
}
2012-02-02 02:13:02 +01:00
return ( ver_maj * REV_MULT ) + ( ( ver_min % REV_MULT ) * 10 ) + ( ver_mod % 10 ) ;
2012-01-30 17:50:19 +01:00
}
2014-02-14 23:14:39 +01:00
bool EncodeThread : : checkVersionVapoursynth ( void )
2013-08-02 20:44:47 +02:00
{
2013-08-04 18:44:53 +02:00
//Is VapourSynth available at all?
2014-02-14 23:14:39 +01:00
if ( ( ! m_sysinfo - > hasVPSSupport ( ) ) | | ( ! QFileInfo ( VPS_BINARY ( m_sysinfo , m_preferences ) ) . isFile ( ) ) )
2013-08-04 18:44:53 +02:00
{
log ( tr ( " \n VPY INPUT REQUIRES VAPOURSYNTH, BUT IT IS *NOT* AVAILABLE !!! " ) ) ;
return false ;
}
2013-08-02 20:44:47 +02:00
QProcess process ;
log ( " \n Creating process: " ) ;
2014-02-14 23:14:39 +01:00
if ( ! startProcess ( process , VPS_BINARY ( m_sysinfo , m_preferences ) , QStringList ( ) ) )
2013-08-02 20:44:47 +02:00
{
return false ; ;
}
QRegExp regExpSignature ( " \\ bVSPipe \\ s+usage \\ b " , Qt : : CaseInsensitive ) ;
bool bTimeout = false ;
bool bAborted = false ;
bool vspipeSignature = false ;
while ( process . state ( ) ! = QProcess : : NotRunning )
{
if ( m_abort )
{
process . kill ( ) ;
bAborted = true ;
break ;
}
if ( ! process . waitForReadyRead ( ) )
{
if ( process . state ( ) = = QProcess : : Running )
{
process . kill ( ) ;
qWarning ( " VSPipe process timed out <-- killing! " ) ;
log ( " \n PROCESS TIMEOUT !!! " ) ;
bTimeout = true ;
break ;
}
}
while ( process . bytesAvailable ( ) > 0 )
{
QList < QByteArray > lines = process . readLine ( ) . split ( ' \r ' ) ;
while ( ! lines . isEmpty ( ) )
{
QString text = QString : : fromUtf8 ( lines . takeFirst ( ) . constData ( ) ) . simplified ( ) ;
if ( regExpSignature . lastIndexIn ( text ) > = 0 )
{
vspipeSignature = true ;
}
if ( ! text . isEmpty ( ) )
{
log ( text ) ;
}
}
}
}
process . waitForFinished ( ) ;
if ( process . state ( ) ! = QProcess : : NotRunning )
{
process . kill ( ) ;
process . waitForFinished ( - 1 ) ;
}
if ( bTimeout | | bAborted | | ( ( process . exitCode ( ) ! = EXIT_SUCCESS ) & & ( process . exitCode ( ) ! = 1 ) ) )
{
if ( ! ( bTimeout | | bAborted ) )
{
log ( tr ( " \n PROCESS EXITED WITH ERROR CODE: %1 " ) . arg ( QString : : number ( process . exitCode ( ) ) ) ) ;
}
return false ;
}
if ( ! vspipeSignature )
{
log ( tr ( " \n FAILED TO DETECT VSPIPE SIGNATURE !!! " ) ) ;
return false ;
}
return vspipeSignature ;
}
2014-02-14 23:14:39 +01:00
bool EncodeThread : : checkPropertiesAVS ( unsigned int & frames )
2012-01-31 00:13:32 +01:00
{
QProcess process ;
2012-02-12 15:58:28 +01:00
QStringList cmdLine ;
if ( ! m_options - > customAvs2YUV ( ) . isEmpty ( ) )
{
cmdLine . append ( splitParams ( m_options - > customAvs2YUV ( ) ) ) ;
}
cmdLine < < " -frames " < < " 1 " ;
2013-11-08 14:15:40 +01:00
cmdLine < < QDir : : toNativeSeparators ( x264_path2ansi ( m_sourceFileName , true ) ) < < " NUL " ;
2012-01-31 00:13:32 +01:00
log ( " Creating process: " ) ;
2014-02-14 23:14:39 +01:00
if ( ! startProcess ( process , AVS_BINARY ( m_sysinfo , m_preferences ) , cmdLine ) )
2012-01-31 00:13:32 +01:00
{
return false ; ;
}
QRegExp regExpInt ( " : ( \\ d+) x ( \ \ d + ) , ( \ \ d + ) fps , ( \ \ d + ) frames " ) ;
QRegExp regExpFrc ( " : ( \\ d+) x ( \ \ d + ) , ( \ \ d + ) / ( \ \ d + ) fps , ( \ \ d + ) frames " ) ;
2012-02-05 21:52:23 +01:00
QTextCodec * localCodec = QTextCodec : : codecForName ( " System " ) ;
2012-01-31 00:13:32 +01:00
bool bTimeout = false ;
bool bAborted = false ;
frames = 0 ;
unsigned int fpsNom = 0 ;
unsigned int fpsDen = 0 ;
unsigned int fSizeW = 0 ;
unsigned int fSizeH = 0 ;
2012-02-11 16:10:21 +01:00
unsigned int waitCounter = 0 ;
2012-01-31 00:13:32 +01:00
while ( process . state ( ) ! = QProcess : : NotRunning )
{
if ( m_abort )
{
process . kill ( ) ;
bAborted = true ;
break ;
}
2012-02-11 16:10:21 +01:00
if ( ! process . waitForReadyRead ( m_processTimeoutInterval ) )
2012-01-31 00:13:32 +01:00
{
if ( process . state ( ) = = QProcess : : Running )
{
2013-08-04 18:44:53 +02:00
if ( + + waitCounter > m_processTimeoutMaxCounter )
2012-02-11 16:10:21 +01:00
{
2014-02-14 23:14:39 +01:00
if ( m_preferences - > getAbortOnTimeout ( ) )
2013-08-04 18:44:53 +02:00
{
process . kill ( ) ;
qWarning ( " Avs2YUV process timed out <-- killing! " ) ;
log ( " \n PROCESS TIMEOUT !!! " ) ;
log ( " \n Avisynth has encountered a deadlock or your script takes EXTREMELY long to initialize! " ) ;
bTimeout = true ;
break ;
}
2012-02-11 16:10:21 +01:00
}
else if ( waitCounter = = m_processTimeoutWarning )
{
unsigned int timeOut = ( waitCounter * m_processTimeoutInterval ) / 1000U ;
log ( tr ( " Warning: Avisynth did not respond for %1 seconds, potential deadlock... " ) . arg ( QString : : number ( timeOut ) ) ) ;
}
2012-01-31 00:13:32 +01:00
}
2012-02-11 16:10:21 +01:00
continue ;
2012-01-31 00:13:32 +01:00
}
2012-02-11 16:10:21 +01:00
waitCounter = 0 ;
2012-01-31 00:13:32 +01:00
while ( process . bytesAvailable ( ) > 0 )
{
QList < QByteArray > lines = process . readLine ( ) . split ( ' \r ' ) ;
while ( ! lines . isEmpty ( ) )
{
2012-02-05 21:52:23 +01:00
QString text = localCodec - > toUnicode ( lines . takeFirst ( ) . constData ( ) ) . simplified ( ) ;
2012-01-31 00:13:32 +01:00
int offset = - 1 ;
if ( ( offset = regExpInt . lastIndexIn ( text ) ) > = 0 )
{
bool ok1 = false , ok2 = false ;
bool ok3 = false , ok4 = false ;
unsigned int temp1 = regExpInt . cap ( 1 ) . toUInt ( & ok1 ) ;
unsigned int temp2 = regExpInt . cap ( 2 ) . toUInt ( & ok2 ) ;
unsigned int temp3 = regExpInt . cap ( 3 ) . toUInt ( & ok3 ) ;
unsigned int temp4 = regExpInt . cap ( 4 ) . toUInt ( & ok4 ) ;
if ( ok1 ) fSizeW = temp1 ;
if ( ok2 ) fSizeH = temp2 ;
if ( ok3 ) fpsNom = temp3 ;
if ( ok4 ) frames = temp4 ;
}
else if ( ( offset = regExpFrc . lastIndexIn ( text ) ) > = 0 )
{
bool ok1 = false , ok2 = false ;
bool ok3 = false , ok4 = false , ok5 = false ;
unsigned int temp1 = regExpFrc . cap ( 1 ) . toUInt ( & ok1 ) ;
unsigned int temp2 = regExpFrc . cap ( 2 ) . toUInt ( & ok2 ) ;
unsigned int temp3 = regExpFrc . cap ( 3 ) . toUInt ( & ok3 ) ;
unsigned int temp4 = regExpFrc . cap ( 4 ) . toUInt ( & ok4 ) ;
unsigned int temp5 = regExpFrc . cap ( 5 ) . toUInt ( & ok5 ) ;
if ( ok1 ) fSizeW = temp1 ;
if ( ok2 ) fSizeH = temp2 ;
if ( ok3 ) fpsNom = temp3 ;
if ( ok4 ) fpsDen = temp4 ;
if ( ok5 ) frames = temp5 ;
}
if ( ! text . isEmpty ( ) )
{
log ( text ) ;
}
2012-02-05 02:49:08 +01:00
if ( text . contains ( " failed to load avisynth.dll " , Qt : : CaseInsensitive ) )
{
2014-02-14 23:14:39 +01:00
log ( tr ( " \n Warning: It seems that %1-Bit Avisynth is not currently installed !!! " ) . arg ( m_preferences - > getUseAvisyth64Bit ( ) ? " 64 " : " 32 " ) ) ;
2012-02-05 02:49:08 +01:00
}
2012-02-12 15:58:28 +01:00
if ( text . contains ( QRegExp ( " couldn't convert input clip to (YV16|YV24) " , Qt : : CaseInsensitive ) ) )
{
log ( tr ( " \n Warning: YV16 (4:2:2) and YV24 (4:4:4) color-spaces only supported in Avisynth 2.6 !!! " ) ) ;
}
2012-01-31 00:13:32 +01:00
}
}
}
process . waitForFinished ( ) ;
if ( process . state ( ) ! = QProcess : : NotRunning )
{
process . kill ( ) ;
process . waitForFinished ( - 1 ) ;
}
if ( bTimeout | | bAborted | | process . exitCode ( ) ! = EXIT_SUCCESS )
{
if ( ! ( bTimeout | | bAborted ) )
{
2013-11-10 18:32:37 +01:00
const int exitCode = process . exitCode ( ) ;
log ( tr ( " \n PROCESS EXITED WITH ERROR CODE: %1 " ) . arg ( QString : : number ( exitCode ) ) ) ;
2013-11-29 20:27:45 +01:00
if ( ( exitCode < 0 ) | | ( exitCode > = 32 ) )
2013-11-10 18:32:37 +01:00
{
log ( tr ( " \n IMPORTANT: The Avs2YUV process terminated abnormally. This means Avisynth or one of your Avisynth-Plugin's just crashed. " ) ) ;
log ( tr ( " IMPORTANT: Please fix your Avisynth script and try again! If you use Avisynth-MT, try using a *stable* Avisynth instead! " ) ) ;
}
2012-01-31 00:13:32 +01:00
}
return false ;
}
if ( frames = = 0 )
{
log ( tr ( " \n FAILED TO DETERMINE AVS PROPERTIES !!! " ) ) ;
return false ;
}
log ( " " ) ;
if ( ( fSizeW > 0 ) & & ( fSizeH > 0 ) )
{
log ( tr ( " Resolution: %1x%2 " ) . arg ( QString : : number ( fSizeW ) , QString : : number ( fSizeH ) ) ) ;
}
if ( ( fpsNom > 0 ) & & ( fpsDen > 0 ) )
{
log ( tr ( " Frame Rate: %1/%2 " ) . arg ( QString : : number ( fpsNom ) , QString : : number ( fpsDen ) ) ) ;
}
if ( ( fpsNom > 0 ) & & ( fpsDen = = 0 ) )
{
log ( tr ( " Frame Rate: %1 " ) . arg ( QString : : number ( fpsNom ) ) ) ;
}
if ( frames > 0 )
{
log ( tr ( " No. Frames: %1 " ) . arg ( QString : : number ( frames ) ) ) ;
}
return true ;
}
2014-02-14 23:14:39 +01:00
bool EncodeThread : : checkPropertiesVPS ( unsigned int & frames )
2013-08-02 20:44:47 +02:00
{
QProcess process ;
QStringList cmdLine ;
2013-11-08 14:15:40 +01:00
cmdLine < < QDir : : toNativeSeparators ( x264_path2ansi ( m_sourceFileName , true ) ) ;
2013-08-02 20:44:47 +02:00
cmdLine < < " - " < < " -info " ;
log ( " Creating process: " ) ;
2014-02-14 23:14:39 +01:00
if ( ! startProcess ( process , VPS_BINARY ( m_sysinfo , m_preferences ) , cmdLine ) )
2013-08-02 20:44:47 +02:00
{
return false ; ;
}
QRegExp regExpFrm ( " \\ bFrames: \\ s+( \\ d+) \ \ b " ) ;
QRegExp regExpSzW ( " \\ bWidth: \\ s+( \\ d+) \ \ b " ) ;
QRegExp regExpSzH ( " \\ bHeight: \\ s+( \\ d+) \ \ b " ) ;
QTextCodec * localCodec = QTextCodec : : codecForName ( " System " ) ;
bool bTimeout = false ;
bool bAborted = false ;
frames = 0 ;
unsigned int fSizeW = 0 ;
unsigned int fSizeH = 0 ;
unsigned int waitCounter = 0 ;
while ( process . state ( ) ! = QProcess : : NotRunning )
{
if ( m_abort )
{
process . kill ( ) ;
bAborted = true ;
break ;
}
if ( ! process . waitForReadyRead ( m_processTimeoutInterval ) )
{
if ( process . state ( ) = = QProcess : : Running )
{
2013-08-04 18:44:53 +02:00
if ( + + waitCounter > m_processTimeoutMaxCounter )
2013-08-02 20:44:47 +02:00
{
2014-02-14 23:14:39 +01:00
if ( m_preferences - > getAbortOnTimeout ( ) )
2013-08-04 18:44:53 +02:00
{
process . kill ( ) ;
qWarning ( " VSPipe process timed out <-- killing! " ) ;
log ( " \n PROCESS TIMEOUT !!! " ) ;
log ( " \n Vapoursynth has encountered a deadlock or your script takes EXTREMELY long to initialize! " ) ;
bTimeout = true ;
break ;
}
2013-08-02 20:44:47 +02:00
}
else if ( waitCounter = = m_processTimeoutWarning )
{
unsigned int timeOut = ( waitCounter * m_processTimeoutInterval ) / 1000U ;
log ( tr ( " Warning: nVapoursynth did not respond for %1 seconds, potential deadlock... " ) . arg ( QString : : number ( timeOut ) ) ) ;
}
}
continue ;
}
waitCounter = 0 ;
while ( process . bytesAvailable ( ) > 0 )
{
QList < QByteArray > lines = process . readLine ( ) . split ( ' \r ' ) ;
while ( ! lines . isEmpty ( ) )
{
QString text = localCodec - > toUnicode ( lines . takeFirst ( ) . constData ( ) ) . simplified ( ) ;
int offset = - 1 ;
if ( ( offset = regExpFrm . lastIndexIn ( text ) ) > = 0 )
{
bool ok = false ;
unsigned int temp = regExpFrm . cap ( 1 ) . toUInt ( & ok ) ;
if ( ok ) frames = temp ;
}
if ( ( offset = regExpSzW . lastIndexIn ( text ) ) > = 0 )
{
bool ok = false ;
unsigned int temp = regExpSzW . cap ( 1 ) . toUInt ( & ok ) ;
if ( ok ) fSizeW = temp ;
}
if ( ( offset = regExpSzH . lastIndexIn ( text ) ) > = 0 )
{
bool ok = false ;
unsigned int temp = regExpSzH . cap ( 1 ) . toUInt ( & ok ) ;
if ( ok ) fSizeH = temp ;
}
if ( ! text . isEmpty ( ) )
{
log ( text ) ;
}
}
}
}
process . waitForFinished ( ) ;
if ( process . state ( ) ! = QProcess : : NotRunning )
{
process . kill ( ) ;
process . waitForFinished ( - 1 ) ;
}
if ( bTimeout | | bAborted | | process . exitCode ( ) ! = EXIT_SUCCESS )
{
if ( ! ( bTimeout | | bAborted ) )
{
2013-11-10 18:32:37 +01:00
const int exitCode = process . exitCode ( ) ;
log ( tr ( " \n PROCESS EXITED WITH ERROR CODE: %1 " ) . arg ( QString : : number ( exitCode ) ) ) ;
2013-11-29 20:27:45 +01:00
if ( ( exitCode < 0 ) | | ( exitCode > = 32 ) )
2013-11-10 18:32:37 +01:00
{
log ( tr ( " \n IMPORTANT: The Vapoursynth process terminated abnormally. This means Vapoursynth or one of your Vapoursynth-Plugin's just crashed. " ) ) ;
}
2013-08-02 20:44:47 +02:00
}
return false ;
}
if ( frames = = 0 )
{
log ( tr ( " \n FAILED TO DETERMINE VPY PROPERTIES !!! " ) ) ;
return false ;
}
log ( " " ) ;
if ( ( fSizeW > 0 ) & & ( fSizeH > 0 ) )
{
log ( tr ( " Resolution: %1x%2 " ) . arg ( QString : : number ( fSizeW ) , QString : : number ( fSizeH ) ) ) ;
}
if ( frames > 0 )
{
log ( tr ( " No. Frames: %1 " ) . arg ( QString : : number ( frames ) ) ) ;
}
return true ;
}
2012-01-29 21:31:09 +01:00
///////////////////////////////////////////////////////////////////////////////
// Misc functions
///////////////////////////////////////////////////////////////////////////////
2012-01-30 04:58:42 +01:00
void EncodeThread : : setStatus ( JobStatus newStatus )
{
if ( m_status ! = newStatus )
{
2012-02-02 02:13:02 +01:00
if ( ( newStatus ! = JobStatus_Completed ) & & ( newStatus ! = JobStatus_Failed ) & & ( newStatus ! = JobStatus_Aborted ) & & ( newStatus ! = JobStatus_Paused ) )
2012-01-30 17:50:19 +01:00
{
2012-02-03 02:26:08 +01:00
if ( m_status ! = JobStatus_Paused ) setProgress ( 0 ) ;
2012-01-30 17:50:19 +01:00
}
if ( newStatus = = JobStatus_Failed )
{
setDetails ( " The job has failed. See log for details! " ) ;
}
if ( newStatus = = JobStatus_Aborted )
{
setDetails ( " The job was aborted by the user! " ) ;
}
2012-02-03 02:26:08 +01:00
m_status = newStatus ;
2012-01-30 04:58:42 +01:00
emit statusChanged ( m_jobId , newStatus ) ;
}
}
void EncodeThread : : setProgress ( unsigned int newProgress )
{
if ( m_progress ! = newProgress )
{
m_progress = newProgress ;
emit progressChanged ( m_jobId , m_progress ) ;
}
}
void EncodeThread : : setDetails ( const QString & text )
{
emit detailsChanged ( m_jobId , text ) ;
}
2013-08-28 18:10:26 +02:00
QString EncodeThread : : stringToHash ( const QString & string )
{
QByteArray result ( 10 , char ( 0 ) ) ;
const QByteArray hash = QCryptographicHash : : hash ( string . toUtf8 ( ) , QCryptographicHash : : Sha1 ) ;
if ( ( hash . size ( ) = = 20 ) & & ( result . size ( ) = = 10 ) )
2012-02-05 21:52:23 +01:00
{
2013-08-28 18:10:26 +02:00
unsigned char * out = reinterpret_cast < unsigned char * > ( result . data ( ) ) ;
const unsigned char * in = reinterpret_cast < const unsigned char * > ( hash . constData ( ) ) ;
for ( int i = 0 ; i < 10 ; i + + )
{
out [ i ] = ( in [ i ] ^ in [ 10 + i ] ) ;
}
2012-02-05 21:52:23 +01:00
}
2013-08-28 18:10:26 +02:00
return QString : : fromLatin1 ( result . toHex ( ) . constData ( ) ) ;
2012-02-05 21:52:23 +01:00
}
2012-01-31 15:15:15 +01:00
bool EncodeThread : : startProcess ( QProcess & process , const QString & program , const QStringList & args , bool mergeChannels )
2012-01-29 21:31:09 +01:00
{
QMutexLocker lock ( & m_mutex_startProcess ) ;
log ( commandline2string ( program , args ) + " \n " ) ;
2012-01-31 00:13:32 +01:00
2013-08-27 21:33:50 +02:00
process . setWorkingDirectory ( QDir : : tempPath ( ) ) ;
2012-01-31 15:15:15 +01:00
if ( mergeChannels )
{
process . setProcessChannelMode ( QProcess : : MergedChannels ) ;
process . setReadChannel ( QProcess : : StandardOutput ) ;
}
else
{
process . setProcessChannelMode ( QProcess : : SeparateChannels ) ;
process . setReadChannel ( QProcess : : StandardError ) ;
}
2012-01-29 21:31:09 +01:00
process . start ( program , args ) ;
if ( process . waitForStarted ( ) )
{
2013-11-03 18:59:29 +01:00
m_jobObject - > addProcessToJob ( & process ) ;
2014-02-14 23:14:39 +01:00
x264_change_process_priority ( & process , m_preferences - > getProcessPriority ( ) ) ;
2012-01-29 21:31:09 +01:00
lock . unlock ( ) ;
return true ;
2012-01-29 00:57:47 +01:00
}
2012-01-29 21:31:09 +01:00
log ( " Process creation has failed :-( " ) ;
QString errorMsg = process . errorString ( ) . trimmed ( ) ;
if ( ! errorMsg . isEmpty ( ) ) log ( errorMsg ) ;
2012-01-29 00:57:47 +01:00
2012-01-29 21:31:09 +01:00
process . kill ( ) ;
process . waitForFinished ( - 1 ) ;
return false ;
}
QString EncodeThread : : 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 ;
2012-01-28 18:55:40 +01:00
}
2012-02-06 22:40:07 +01:00
QStringList EncodeThread : : splitParams ( const QString & params )
{
QStringList list ;
2012-02-07 21:48:25 +01:00
bool ignoreWhitespaces = false ;
2012-02-06 22:40:07 +01:00
QString temp ;
for ( int i = 0 ; i < params . length ( ) ; i + + )
{
const QChar c = params . at ( i ) ;
if ( c = = QChar : : fromLatin1 ( ' " ' ) )
{
2012-02-07 21:48:25 +01:00
ignoreWhitespaces = ( ! ignoreWhitespaces ) ;
2012-02-06 22:40:07 +01:00
continue ;
}
2012-02-07 21:48:25 +01:00
else if ( ( ! ignoreWhitespaces ) & & ( c = = QChar : : fromLatin1 ( ' ' ) ) )
2012-02-06 22:40:07 +01:00
{
APPEND_AND_CLEAR ( list , temp ) ;
continue ;
}
temp . append ( c ) ;
}
APPEND_AND_CLEAR ( list , temp ) ;
2012-02-14 20:50:35 +01:00
list . replaceInStrings ( " $(INPUT) " , QDir : : toNativeSeparators ( m_sourceFileName ) , Qt : : CaseInsensitive ) ;
list . replaceInStrings ( " $(OUTPUT) " , QDir : : toNativeSeparators ( m_outputFileName ) , Qt : : CaseInsensitive ) ;
2012-02-06 22:40:07 +01:00
return list ;
2012-02-23 03:18:46 +01:00
}
2012-02-27 21:39:15 +01:00
qint64 EncodeThread : : estimateSize ( int progress )
{
if ( progress > = 3 )
{
qint64 currentSize = QFileInfo ( m_outputFileName ) . size ( ) ;
qint64 estimatedSize = ( currentSize * 100 I64 ) / static_cast < qint64 > ( progress ) ;
return estimatedSize ;
}
return 0 I64 ;
}
QString EncodeThread : : sizeToString ( qint64 size )
2012-02-23 03:18:46 +01:00
{
static char * prefix [ 5 ] = { " Byte " , " KB " , " MB " , " GB " , " TB " } ;
2012-02-27 21:39:15 +01:00
if ( size > 1024 I64 )
2012-02-23 03:18:46 +01:00
{
2012-02-27 21:39:15 +01:00
qint64 estimatedSize = size ;
qint64 remainderSize = 0 I64 ;
2012-02-23 03:18:46 +01:00
2012-02-27 21:39:15 +01:00
int prefixIdx = 0 ;
while ( ( estimatedSize > 1024 I64 ) & & ( prefixIdx < 4 ) )
{
remainderSize = estimatedSize % 1024 I64 ;
estimatedSize = estimatedSize / 1024 I64 ;
prefixIdx + + ;
2012-02-23 03:18:46 +01:00
}
2012-02-27 21:39:15 +01:00
double value = static_cast < double > ( estimatedSize ) + ( static_cast < double > ( remainderSize ) / 1024.0 ) ;
return QString ( ) . sprintf ( ( value < 10.0 ) ? " %.2f %s " : " %.1f %s " , value , prefix [ prefixIdx ] ) ;
2012-02-23 03:18:46 +01:00
}
return tr ( " N/A " ) ;
}
2013-07-03 21:34:21 +02:00
2013-08-02 20:44:47 +02:00
int EncodeThread : : getInputType ( const QString & fileExt )
{
int type = INPUT_NATIVE ;
if ( fileExt . compare ( " avs " , Qt : : CaseInsensitive ) = = 0 ) type = INPUT_AVISYN ;
else if ( fileExt . compare ( " avsi " , Qt : : CaseInsensitive ) = = 0 ) type = INPUT_AVISYN ;
else if ( fileExt . compare ( " vpy " , Qt : : CaseInsensitive ) = = 0 ) type = INPUT_VAPOUR ;
else if ( fileExt . compare ( " py " , Qt : : CaseInsensitive ) = = 0 ) type = INPUT_VAPOUR ;
return type ;
}