/*****************************************************************************
 *
 *  interfacemencoder.cpp -- Interface to Mencoder CLI.
 *
 *  Copyright (C) 2010 Starbuck <starbuck@labdv.com>
 *  All rights reserved.
 *
 *  This file is part of the Encoder module of the DVDx 4 application.
 *
 *  GNU Lesser General Public License Usage
 *  This file may be used under the terms of the GNU Lesser General
 *  Public License version 2.1 as published by the Free Software
 *  Foundation and appearing in the file LICENSE.LGPL included in the
 *  packaging of this file.  Please review the following information to
 *  ensure the GNU Lesser General Public License version 2.1 requirements
 *  will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 *
 *  GNU General Public License Usage
 *  Alternatively, this file may be used under the terms of the GNU
 *  General Public License version 3.0 as published by the Free Software
 *  Foundation and appearing in the file LICENSE.GPL included in the
 *  packaging of this file.  Please review the following information to
 *  ensure the GNU General Public License version 3.0 requirements will be
 *  met: http://www.gnu.org/copyleft/gpl.html.
 *
 *****************************************************************************/

#define	RX_CATCH_MENCODER_OUTPUT_STATUS	"(mencoder\\s+[^\\s]+.*MPlayer Team)"
#define	RX_CATCH_MENCODER_OUTPUT_HELP	"Available codecs:(.*)Available codecs:(.*)Available output formats:(.*)"

#define	RX_PARSE_MENCODER_SIGNATURE		"(mencoder)\\s+([^\\s]+).*(MPlayer Team)"
#ifdef WIN32
#define	RX_PARSE_MENCODER_VAF_HELP		"([^\\s]+)\\s+-\\s+([^\\n]*)\\r\\n"
#define	RX_PARSE_MENCODER_OUTPUT_HELP	"([^\\s]+)\\s+-\\s+([^\\n]*)\\r\\n"
#else
#define	RX_PARSE_MENCODER_VAF_HELP		"([^\\s]+)\\s+-\\s+([^\\n]*)\\n"
#define	RX_PARSE_MENCODER_OUTPUT_HELP	"([^\\s]+)\\s+-\\s+([^\\n]*)\\n"
#endif

#define	RX_PARSE_MENCODER_OUTPUT_VALID	"Pos:(.*)s(.*)f(.*)%(.*)fps"
#define	RX_PARSE_MENCODER_PROGRESS		"Pos:\\s*([\\d\\.]*)s.*([\\d\\.]*)f.*\\(\\s*(\\d+)%\\).*([\\d\\.]+)fps.*Trem:\\s*(\\d+)min"

#include "../video/video_functions.h"
#include "interfacemencoder.h"
#include "macros.h"
#include <math.h>
#include <QProcess>
#include <QDir>
#include <QList>
#include <QRegExp>
#include <QDebug>

InterfaceMEncoder::InterfaceMEncoder()
{
	setVideoSynonyms();
	setAudioSynonyms();
	setSubtitleSynonyms();
	setMuxerSynonyms();

	// Supported codecs and muxers
	muxers = new QStringList;
	videos = new QStringList;
	audios = new QStringList;
	subtitles = new QStringList;

	*muxers << "avi" << "mpeg" << "lavf" /*<< "rawaudio" << "rawvideo"*/;

	*videos << "copy" << "xvid" << "frameno" << "lavc" /*<< "nuv" << "raw"*/ << "x264";

	*audios << "copy" << "faac" << "mp3lame" /*<< "twolame"*/ << "lavc";
	
	*subtitles << "inlay";

	// Virtual muxers
	*muxers << "mpeg_vcd";

	// Supported FFmpeg lib codecs and muxers
	libffSupport[ "muxer" ] = QStringList();
	libffSupport[ "video" ] = QStringList();
	libffSupport[ "audio" ] = QStringList();
	libffSupport[ "subtitle" ] = QStringList();

	libffSupport[ "muxer" ] << "3g2" << "3gp" << "ac3" << "adts" << "aiff" 
		<< "amr" << "asf" << "au" << "avi" << "avm2" 
		<< "dts" << "dv" << "dvd" << "f64be" << "f64le" << "filmstrip" << "flac" << "flv" 
		<< "h263" << "h264" << "ipod" << "m4a" << "m4v" << "matroska" << "mov" << "mp2" << "mp3" << "mp4"
		<< "mpeg" << "mpeg1video" << "mpeg2video" << "mpegts" << "mxf" << "nut" << "ogg" << "psp"
		<< "rawvideo" << "rcv" << "rm" << "RoQ" 
		<< "s16be" << "s16le" << "s32be" << "s32le" << "s64be" << "s64le" << "spdif" 
		<< "svcd" << "swf" << "vcd" << "vob" << "wav" << "webm";;
	
	libffSupport[ "video" ] << "dvvideo" << "dnxhd" << "ffv1" << "ffvhuff" << "flashsv" << "flv" 
		<< "h263" << "huffyuv"
		/*<< "libtheora"*/ << "libx264" << "libxvid" 
		<< "ljpeg" << "mjpeg" << "mpeg1video" << "mpeg2video" 
		<< "mpeg4" << "msmpeg4" << "msmpeg4v1" << "msmpeg4v2" << "novideo"
		<< "qtrle" << "rawvideo" << "roqvideo" << "rv10" << "rv20" 
		<< "snow" << "svq1" << "wmv1" << "wmv2";

	libffSupport[ "audio" ] /*<< "aac" << "ac3" << "alac"*/ 
		<< "adpcm_ima_qt" << "adpcm_ima_wav" << "adpcm_ms" << "adpcm_swf"
		<< "copy" << "flac" << "g726"
		/*<< "libfaac"*/ << "libgsm" << "libmp3lame" << "libopencore_amrnb" << "libvorbis" 
		<< "mp2" << "multi" << "noaudio" /*<< "pcm" << "pcm_alaw"*/ 
		/*<< "pcm_s16be" << "pcm_s16le" << "pcm_s32be" << "pcm_s32le" << "pcm_f64be" << "pcm_f64le"*/ 
		<< "roq_dpcm" << "sonic" << "sonicls" << "vorbis" << "wmav1" << "wmav2";
	
	for (int i = 0; i < muxers->count(); i++)
	{
		muxerVideos.insert( (*muxers)[i], QStringList() );
		muxerAudios.insert( (*muxers)[i], QStringList() );
		muxerSubtitles.insert( (*muxers)[i], QStringList() );
	}

	// Muxer -> codecs
	muxerVideos["3g2"] << "h263" << "x264" << "libx264" << "mpeg4" /*<< "xvid" << "libxvid"*/;
	muxerAudios["3g2"] << "aac" << "faac" << "libfaac" /*experimental resampling issue << "libopencore_amrnb"*/ << "noaudio";
	muxerSubtitles["3g2"] << "inlay" << "nosubtitle";

	muxerVideos["3gp"] << "h263" << "x264" << "libx264" << "mpeg4" /*<< "xvid" << "libxvid"*/;
	muxerAudios["3gp"] << "aac" << "faac" << "libfaac" /*<< "libopencore_amrnb"*/ << "noaudio";
	muxerSubtitles["3gp"] << "inlay" << "nosubtitle";

	/*experimental
	muxerVideos["asf"] << "wmv1" << "wmv2";
	muxerAudios["asf"] << "wmav1" << "wmav2";
	muxerSubtitles["asf"] << "inlay";
	*/

	muxerVideos["avi"]	/*<< "dvvideo" << "dnxhd" << "ffv1" << "ffvhuff" << "huffyuv"<< "ljpeg" << "mjpeg"*/ 
						/*<< "mpeg4" << "msmpeg4" << "msmpeg4v1" << "msmpeg4v2"*/ 
						<< "xvid" << "libxvid";
	muxerAudios["avi"] << "aac" << "faac" /*<< "libfaac"*/ << "ac3_copy" /*<< "alac" << "adpcm_ms" */ 
						/*<< "g726"*/
						/*<< "libfaac" << "libgsm" << "libmp3lame"*/ << "mp3"
						/*<< "mp2" << "multi" */
						<< "pcm" /*<< "pcm_s16le" << "pcm_s32le"<< "pcm_f64le"*/;
	muxerSubtitles["avi"] << "inlay" /*<< "xsub"*/;

	/*experimental
	muxerVideos["dv"] << "dvvideo";
	muxerAudios["dv"] << "ac3_copy" 
						<< "pcm" << "pcm_s16le" ;
	muxerSubtitles["dv"] << "inlay";
	*/

	muxerVideos["flv"] << "x264" << "libx264" /*<< "svq1"*/;
	muxerAudios["flv"] << "aac_flv" << "faac" << "libfaac" /*<< "adpcm_swf"*/
						/*  << "libmp3lame"*/ << "mp3_flv" << "mp3_flv_lr"
						/*<< "pcm" << "pcm_s16le" << "pcm_s32le" << "pcm_f64le"*/;
	muxerSubtitles["flv"] << "inlay";

	muxerVideos["ipod"] << "copy" << "x264" << "x264_lr" << "x264_hd" /*<< "xvid"*/ << "libxvid" << "mpeg4";
	muxerAudios["ipod"]  << "copy" << "aac" << "aac_hq" << "aac_lr";
	muxerSubtitles["ipod"] << "inlay";

	muxerVideos["matroska"] /*<< "dvvideo" << "dnxhd" << "ffv1" << "ffvhuff" << "huffyuv" */
							<< "x264" /*<< "x264_lr"*/ << "x264_hd" << "x264_divx"
							/*<< "mpeg4" << "msmpeg4" << "msmpeg4v1" << "msmpeg4v2"*/
							<< "vp8" << "libvpx"
							/*<< "libtheora"*/ << "xvid" /*<< "libxvid"*/;
	muxerAudios["matroska"] /*<< "aac" << "aac_hq" << "faac" << "libfaac"*/ 
							<< "ac3_copy" /*<< "alac" << "adpcm_ms" */ 
							<< "flac" /*<< "g726"*/
							/*<< "libfaac" << "libgsm"*/ << "libmp3lame" << "mp3"
							<< "mp2" /*<< "multi" */
							<< "pcm" << "pcm_s16le" << "pcm_s32le"<< "pcm_f64le"
							<< "libvorbis";
	muxerSubtitles["matroska"] << "inlay" /*<< "xsub"*/;

	muxerVideos["mov"] /*<< "h263"*/ << "copy" << "x264" << "libx264" << "mpeg4" /*<< "qtrle" << "svq1"*/
						/*<< "xvid" << "libxvid"*/;
	muxerAudios["mov"] << "copy" << "aac" << "aac_hq" << "faac" << "libfaac" /*<< "ac3" << "ac3_copy"*/ 
						<< "alac" /*<< "adpcm_ima_qt"*/
						<< "amrnb" << "libopencore_amrnb" << "auto"
						<<"libmp3lame" << "mp3"  << "mp3_lr" /*<< "mp2"*/
						<< "pcm" << "pcm_s16le" << "pcm_s32le" << "pcm_s64le" << "pcm_alaw";
	muxerSubtitles["mov"] << "inlay";

	muxerVideos["mp4"] << "h263" << "x264" << "libx264" << "x264_lr" << "mpeg4" /*<< "xvid" << "libxvid"*/;
	muxerAudios["mp4"]   << "aac" << "aac_hq" << "faac" << "libfaac" << "ac3_copy" 
						<< "libmp3lame" << "mp3"  << "mp3_lr"<< "mp2" ;
	muxerSubtitles["mp4"] << "inlay";

	muxerVideos["mpeg"] << "mpeg2video";
	muxerAudios["mpeg"] << "mp2" << "ac3_copy" /*<< "libmp3lame" << "mp3" << "multi"*/ 
						<< "pcm" << "pcm_s16be" << "pcm_s32be";
	muxerSubtitles["mpeg"] /*<< "dvdsub"*/ << "inlay";

	muxerVideos["mpeg_vcd"] << "mpeg1video";
	muxerAudios["mpeg_vcd"] << "mp2_vcd";
	muxerSubtitles["mpeg_vcd"] << "inlay";

	muxerVideos["mpeg"] << "mpeg2video";
	muxerAudios["mpeg"] << "mp2" << "ac3_copy" /*<< "libmp3lame" << "mp3" << "multi"*/ 
						<< "pcm" << "pcm_s16be" << "pcm_s32be";
	muxerSubtitles["mpeg"] /*<< "dvdsub"*/ << "inlay";

	//*experimental will be worth it with H.264 working
	//muxerVideos["mpegts"] << "mpeg1video" << "mpeg2video" << "mpeg4"
	//						/*<< "x264" << "libx264" << "xvid" << "libxvid"*/;
	//muxerAudios["mpegts"] /*<< "aac" << "faac" << "libfaac" <<*/ "ac3_copy" << "mp2" 
	//						/*<< "libmp3lame" << "mp3" << "multi"*/ 
	//						/*<< "pcm" << "pcm_s16be" << "pcm_s32be"*/;
	//muxerSubtitles["mpegts"] /*<< "dvdsub"*/ << "inlay";

	/*experimental
	muxerVideos["mxf"] << "dnxhd" << "dvvideo" << "mpeg2video";
	muxerAudios["mxf"] << "aac" << "faac" << "libfaac" << "ac3_copy" 
						<< "libmp3lame" << "mp3" << "mp2" << "multi"
						<< "pcm" << "pcm_s16le" << "pcm_s24le";
	muxerSubtitles["mxf"] << "inlay" << "nosubtitle";
	*/

	muxerVideos["ogg"] << "libtheora" << "theora";				// since 2009, OGG is Theora+Vorbis for HTML5 (Firefox)
	muxerAudios["ogg"] << "flac" << "libvorbis" << "vorbis";	// we don't want ogv, ogm and oga (sounds no future)
	muxerSubtitles["ogg"] << "inlay";

	muxerVideos["psp"] << "x264_psp" << "x264_lr";
	muxerAudios["psp"]  << "aac" << "aac_lr";
	muxerSubtitles["psp"] << "inlay";

	/*experimental
	muxerVideos["rm"] << "rv10" << "rv20" ;
	muxerAudios["rm"] << "aac" << "faac" << "libfaac" << "libvorbis";
	muxerSubtitles["rm"] << "inlay";
	*/
	/*experimental
	muxerVideos["swf"] << "flashsv" << "flv" << "svq1";
	muxerAudios["swf"] << "aac" << "faac" << "libfaac" << "adpcm_swf" << "libmp3lame" << "mp3";
	muxerSubtitles["swf"] << "inlay";
	*/

	muxerVideos["webm"] << "vp8";
	muxerAudios["webm"] << "vorbis";
	muxerSubtitles["webm"] << "inlay";

	// Audio formats (muxerVideos.isEmpty)
	muxerAudios["ac3"] << "ac3_copy" /*<< "rawaudio"*/;
	muxerAudios["au"]; /*<< /*"pcm" << "pcm_s16be" << "pcm_s16le" << "pcm_s32be" << "pcm_s32le";*/
	muxerAudios["mp3"] << "mp3lame"  << "mp3_lr";
	muxerAudios["m4a"] << "aac" /*<< "alac"*/;
	muxerAudios["wav"] << "adpcm_ima_wav" << "libmp3lame" << "mp3";
						/*<< "pcm" << "pcm_s16le" << "pcm_s32le"<< "pcm_f64le"*/;
	// note: aac, mp3 and libmp3lame can be audio only in mpegts thru lavc/lavf

	setCodecSpecific();
}

void InterfaceMEncoder::setMuxerSynonyms()
{
	muxerSynonyms.clear();

	muxerSynonyms[ "mkv" ] = "matroska";
	muxerSynonyms[ "wmv" ] = "asf";
}

void InterfaceMEncoder::setVideoSynonyms()
{
	videoSynonyms.clear();

	videoSynonyms[ "dv" ] = "dvvideo";
	videoSynonyms[ "theora" ] = "libtheora";
	videoSynonyms[ "x264" ] = "libx264";
	videoSynonyms[ "x264_lr" ] = "libx264";
	videoSynonyms[ "x264_hd" ] = "libx264";
	videoSynonyms[ "xvid" ] = "libxvid";
}

void InterfaceMEncoder::setAudioSynonyms()
{
	audioSynonyms.clear();

	audioSynonyms[ "aac" ] = "faac";
	audioSynonyms[ "aac" ] = "libfaac";
	//audioSynonyms[ "aac_lr" ] = "aac";  // AAC LowRate is a virtual codec :-)
	audioSynonyms[ "aac_lr" ] = "faac";
	audioSynonyms[ "aac_lr" ] = "libfaac";
	audioSynonyms[ "amrnb" ] = "libopencore_amrnb";
	audioSynonyms[ "gsm" ] = "libgsm";
	audioSynonyms[ "mp3" ] = "libmp3lame";
	audioSynonyms[ "mp3" ] = "mp3lame";
	audioSynonyms[ "vorbis" ] = "libvorbis";
}

void InterfaceMEncoder::setSubtitleSynonyms()
{
	subtitleSynonyms.clear();
}

void InterfaceMEncoder::setCodecSpecific()
{
	QString preset;
	QString options;
/*
	// x264 specific
	preset = "baseline";
	options = "	coder=0
				bf=0
				flags2=-wpred-dct8x8
				wpredp=0
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "veryslow";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partp4x4+partb8x8
				me_method=umh
				subq=10
				me_range=24
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=2
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=8
				refs=16
				directpred=3
				trellis=2
				flags2=+bpyramid+mixed_refs+wpred+dct8x8+fastpskip
				wpredp=2
				rc_lookahead=60
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "veryslow_firstpass";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=2
				me_range=24
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=2
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=8
				refs=1
				directpred=3
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred-dct8x8+fastpskip
				wpredp=2
				rc_lookahead=60
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "slower";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partp4x4+partb8x8
				me_method=umh
				subq=9
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=2
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=8
				directpred=3
				trellis=2
				flags2=+bpyramid+mixed_refs+wpred+dct8x8+fastpskip
				wpredp=2
				rc_lookahead=60
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "slower_firstpass";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=2
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=2
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=1
				directpred=3
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred-dct8x8+fastpskip
				wpredp=2
				rc_lookahead=60
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "slow";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partb8x8
				me_method=umh
				subq=8
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=2
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=5
				directpred=3
				trellis=1
				flags2=+bpyramid+mixed_refs+wpred+dct8x8+fastpskip
				wpredp=2
				rc_lookahead=50
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "slow_firstpass";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=2
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=2
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=1
				directpred=3
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred-dct8x8+fastpskip
				wpredp=2
				rc_lookahead=50
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "medium";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partb8x8
				me_method=hex
				subq=7
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=3
				directpred=1
				trellis=1
				flags2=+bpyramid+mixed_refs+wpred+dct8x8+fastpskip
				wpredp=2
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "medium_firstpass";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=2
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=1
				directpred=1
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred-dct8x8+fastpskip
				wpredp=2
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "fast";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partb8x8
				me_method=hex
				subq=6
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=2
				directpred=1
				trellis=1
				flags2=+bpyramid+mixed_refs+wpred+dct8x8+fastpskip
				wpredp=2
				rc_lookahead=30
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "fast_firstpass";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=2
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=1
				directpred=1
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred-dct8x8+fastpskip
				wpredp=2
				rc_lookahead=30
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "faster";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partb8x8
				me_method=hex
				subq=4
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=2
				directpred=1
				trellis=1
				flags2=+bpyramid-mixed_refs+wpred+dct8x8+fastpskip
				wpredp=1
				rc_lookahead=20
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "faster_firstpass";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=2
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=1
				directpred=1
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred-dct8x8+fastpskip
				wpredp=1
				rc_lookahead=20
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "veryfast";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partb8x8
				me_method=hex
				subq=2
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=1
				directpred=1
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred+dct8x8+fastpskip
				wpredp=0
				rc_lookahead=10
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "veryfast_firstpass";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=2
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=1
				directpred=1
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred-dct8x8+fastpskip
				wpredp=0
				rc_lookahead=10
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "superfast";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=1
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=1
				directpred=1
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred+dct8x8+fastpskip-mbtree
				wpredp=0
				rc_lookahead=0
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "superfast_firstpass";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=1
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=3
				refs=1
				directpred=1
				trellis=0
				flags2=+bpyramid-mixed_refs+wpred-dct8x8+fastpskip-mbtree
				wpredp=0
				rc_lookahead=0
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "ultrafast";
	options = "	coder=0
				flags=-loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=0
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=0
				i_qfactor=0.71
				b_strategy=0
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=0
				refs=1
				directpred=1
				trellis=0
				flags2=-bpyramid-mixed_refs-wpred-dct8x8+fastpskip-mbtree
				wpredp=0
				aq_mode=0
				rc_lookahead=0
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "ultrafast_firstpass";
	options = "	coder=0
				flags=-loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partb8x8
				me_method=dia
				subq=0
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=0
				i_qfactor=0.71
				b_strategy=0
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=0
				refs=1
				directpred=1
				trellis=0
				flags2=-bpyramid-mixed_refs-wpred-dct8x8+fastpskip-mbtree
				wpredp=0
				aq_mode=0
				rc_lookahead=0
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "lossless_max";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partp4x4-partb8x8
				me_method=esa
				subq=8
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				refs=16
				directpred=1
				flags2=+mixed_refs+dct8x8+fastpskip
				cqp=0
				wpredp=2
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "lossless_slower";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partp4x4-partb8x8
				me_method=umh
				subq=8
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				refs=4
				directpred=1
				flags2=+mixed_refs+dct8x8+fastpskip
				cqp=0
				wpredp=2
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "lossless_slow";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partp4x4-partb8x8
				me_method=umh
				subq=6
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				refs=2
				directpred=1
				flags2=+dct8x8+fastpskip
				cqp=0
				wpredp=2
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "lossless_medium";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partp4x4-partb8x8
				me_method=esa
				subq=8
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				refs=16
				directpred=1
				flags2=+mixed_refs+dct8x8+fastpskip
				cqp=0
				wpredp=2
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "lossless_fast";
	options = "	coder=0
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8+parti4x4+partp8x8-partp4x4-partb8x8
				me_method=hex
				subq=3
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				directpred=1
				flags2=+fastpskip
				cqp=0
				wpredp=0
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "lossless_ultrafast";
	options = "	coder=0
				flags=+loop
				cmp=+chroma
				partitions=-parti8x8-parti4x4-partp8x8-partp4x4-partb8x8
				me_method=dia
				subq=0
				me_range=16
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=1
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				directpred=1
				flags2=+fastpskip
				cqp=0
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "placebo";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partp4x4+partb8x8
				me_method=tesa
				subq=10
				me_range=24
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=2
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=16
				refs=16
				directpred=3
				trellis=2
				flags2=+bpyramid+mixed_refs+wpred+dct8x8-fastpskip
				wpredp=2
				rc_lookahead=60
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "placebo_firstpass";
	options = "	coder=1
				flags=+loop
				cmp=+chroma
				partitions=+parti8x8+parti4x4+partp8x8+partp4x4+partb8x8
				me_method=tesa
				subq=10
				me_range=24
				g=250
				keyint_min=25
				sc_threshold=40
				i_qfactor=0.71
				b_strategy=2
				qcomp=0.6
				qmin=10
				qmax=51
				qdiff=4
				bf=16
				refs=16
				directpred=3
				trellis=2
				flags2=+bpyramid+mixed_refs+wpred+dct8x8-fastpskip
				wpredp=2
				rc_lookahead=60
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "ipod320";
	options = "	coder=0
				bf=0
				flags2=-wpred-dct8x8
				level=13
				maxrate=768000
				bufsize=3000000
				wpredp=0
		";
	x264ffPresets.insert(preset, options.simplified());

	preset = "ipod640";
	options = "	coder=0
				bf=0
				refs=1
				flags2=-wpred-dct8x8
				level=30
				maxrate=10000000
				bufsize=10000000
				wpredp=0
		";
	x264ffPresets.insert(preset, options.simplified());
*/
}

void InterfaceMEncoder::initialize(const QString &p, 
		encoder_engine_capability_t *c, encoder_settings_t *m, encoder_engine_status_t *s)
{
	exec = p;
	capability = c;
	settings = m;
	status = s;

	NPass = 1;	// 1-pass encoding
	currentPass = 1;
}

void InterfaceMEncoder::setBinPath(const QString &binPath)
{
	exec = binPath;
}

QStringList InterfaceMEncoder::getSupportedMuxers()
{
	QStringList supportedMuxers;

	QStringListIterator m(*muxers);
	while (m.hasNext())
	{
		QString muxer = m.next();

		if (muxer == "lavf")
		{
			supportedMuxers << libffSupport["muxer"];
		}
		else
		{
			supportedMuxers << muxer;
		}
	}

	supportedMuxers.sort();
			
	//qDebug() << "InterfaceMEncoder::getSupportedMuxers returns:" << supportedMuxers;

	return supportedMuxers; 
}

bool InterfaceMEncoder::muxerSupport(const QString &muxer)
{
	bool support(false);

	support =  (muxerVideos.contains(muxer) && !muxerVideos[muxer].isEmpty())
			|| (muxerAudios.contains(muxer) && !muxerAudios[muxer].isEmpty())
			|| (muxerSubtitles.contains(muxer) && !muxerSubtitles[muxer].isEmpty());

	if ( !support )
	{
		QStringList synonyms = muxerSynonyms.values(muxer);
		QStringListIterator m(synonyms);
		while (m.hasNext())
		{
			QString mux = m.next();

			support =  (muxerVideos.contains(mux) && !muxerVideos[mux].isEmpty())
					|| (muxerAudios.contains(mux) && !muxerAudios[mux].isEmpty())
					|| (muxerSubtitles.contains(mux) && !muxerSubtitles[mux].isEmpty());

			if (support) break;
		}
	}

	return support;
}

bool InterfaceMEncoder::muxerSupportVideo(const QString &muxer, const QString &video)
{
	bool support(false);

	support = muxerVideos[muxer].contains(video);
	
	if ( !support )
	{
		QStringList synonyms = videoSynonyms.values(video);
		QStringListIterator v(synonyms);
		while (v.hasNext())
		{
			QString vid = v.next();

			support = muxerVideos[muxer].contains(vid);

			if (support) break;
		}
	}

	return support;
}

bool InterfaceMEncoder::muxerSupportAudio(const QString &muxer, const QString &audio)
{
	bool support(false);

	support = muxerAudios[muxer].contains(audio);
	
	if ( !support )
	{
		QStringList synonyms = audioSynonyms.values(audio);
		QStringListIterator a(synonyms);
		while (a.hasNext())
		{
			QString aud = a.next();

			support = muxerAudios[muxer].contains(aud);

			if (support) break;
		}
	}

	return support;
}

bool InterfaceMEncoder::muxerSupportSubtitle(const QString &muxer, const QString &subtitle)
{
	bool support(false);

	support = muxerSubtitles[muxer].contains(subtitle);
	
	if ( !support )
	{
		QStringList synonyms = subtitleSynonyms.values(subtitle);
		QStringListIterator s(synonyms);
		while (s.hasNext())
		{
			QString sub = s.next();

			support = muxerSubtitles[muxer].contains(sub);

			if (support) break;
		}
	}

	return support;
}

bool InterfaceMEncoder::supportMultiAudio()
{
	return audios->contains( "multi" );
}

bool InterfaceMEncoder::supportMultiSubtitle()
{
	return false;  // will be with mkvmerge or ffmpeg as muxer
}

QStringList InterfaceMEncoder::profileCommandLine(const encoder_profile_t *profile, const QString &output,
	int testFrames, int testChapter, int seekPosition)
{
	QString target(output);
	QStringList args;
	QStringList lavcopts;

	// Input
	if ( settings->input.source.media == Video::Media::DVD )
	{
		int title = settings->input.video.title;
		int audioId = settings->input.audio.aid;
		QString audioLang = settings->input.audio.language;
		int subtitleId = settings->input.subtitle.sid;
		QString subtitleLang = settings->input.subtitle.language;
	
		// DVD
		args << "-dvd-device" << settings->input.source.path;
		args << QString("dvd://%1").arg(QString::number(title));

		if (audioId > -1)
		{
			args << "-aid" << QString::number(audioId);
		}
		else if (!audioLang.isEmpty() && audioLang != "en")
		{
			args << "-alang" << QString("%1,en").arg(audioLang);
		}
		else
		{
			args << "-alang" << "en";
		}

		if (subtitleId > -1)
		{
			args << "-sid" << QString::number(subtitleId);
		}
		else if (!subtitleLang.isEmpty() && subtitleLang != "en")
		{
			args << "-slang" << QString("%1,en").arg(subtitleLang);
		}
		else if (!subtitleLang.isEmpty())
		{
			args << "-slang" << "en";
		}
		else
		{
			args << "-nosub";
		}
		
		if (!settings->input.no_video && settings->input.video.angle > 1)
			args << "-dvdangle" << QString::number(settings->input.video.angle);

		if ( testChapter > 0 )
		{
			args << "-chapter" << QString::number(testChapter);
		}
	}
	else
	{
		// File
		args << settings->input.source.path;

		if (!settings->input.no_audio && settings->input.audio.n > -1)
			args << "-aid" << QString::number(settings->input.audio.aid);

		if (!settings->input.no_subtitle && settings->input.subtitle.n > -1)
			args << "-sid" << QString::number(settings->input.subtitle.sid);

		if ( seekPosition > 0 )
		{
			args << "-ss" << QString::number(seekPosition);
		}
	}

	// Testing mode
	if ( testFrames > 0 )
	{
		args << "-frames" << QString::number(testFrames);
	}

	// Encoder options
	args << "-noskip";  // for A/V synchro

	QMapIterator<QString, QString> optionIterator(settings->output.options);
	while (optionIterator.hasNext())
	{
		optionIterator.next();
		if (optionIterator.value().isEmpty())
			args << optionIterator.key();
		else
			args << optionIterator.key() << optionIterator.value();
	}

	// Muxer
	if ( profile->muxer == "avi" ) 
	{
		args << "-of" << "avi";
	}
	else if ( profile->muxer == "mp3" || profile->muxer == "ac3" 
			|| profile->muxer == "au" || profile->muxer == "wav"
			|| profile->muxer == "m4a" )
	{
		QFileInfo fi(output);
		target = fi.path() + "/" + fi.completeBaseName() + " (step 0).avi";

		args << "-of" << "avi"; // audio have to be remuxed from avi to mp3/ac3/au/wav with FFmpeg
	}
	else if ( profile->muxer == "mpeg" || profile->muxer == "mpeg_vcd")
	{
		args << "-of" << "mpeg";

		QStringList mpegopts;

		if ( profile->video.codec == "mpeg1video" )
		{
			mpegopts << "format=xvcd";
		}
		else if ( profile->video.codec == "mpeg2video" 
			&& profile->video.rez.width() < 704  ) 
		{
				mpegopts << "format=xsvcd";
		}
		else if ( profile->video.codec == "mpeg2video" ) 
		{
			mpegopts << "format=dvd";
		}

		if (profile->standard == "PAL")
		{
			args << "-ofps" << "25";
		}
		else if (profile->standard == "NTSC")
		{
			if (settings->input.video.fps < 29.0)
			{
				args << "-ofps" << "24000/1001";
			}
			else
			{
				args << "-ofps" << "30000/1001";
			}
		}

		if ( !mpegopts.isEmpty() )
		{
			args << "-mpegopts" << mpegopts.join(":");
		}
	}
	else
	{
		// Force fps (required for asf and some mov)
		if (profile->muxer == "asf" || profile->muxer == "mov" || profile->muxer == "qt") 
		{
			if (profile->standard == "PAL")
			{
				args << "-ofps" << "25";
			}
			else if (profile->standard == "NTSC")
			{
				if (settings->input.video.fps < 29.0)
				{
					args << "-ofps" << "24000/1001";
				}
				else
				{
					args << "-ofps" << "30000/1001";
				}
			}
			else
			{
				args << "-ofps" << QString::number(settings->input.video.fps);
			}
		}

		// lavf muxer
		args << "-of" << "lavf";

		QString format(profile->muxer);

		if (profile->muxer == "mov")
		{
			format = "qt";
		}
		args << "-lavfopts" << QString("format=%1").arg(format);
	}

	// Video
	QString videoCodec(profile->video.codec);

	if ( videoCodec.isEmpty() || videoCodec == "novideo" )
	{
		args << "-ovc" << "frameno";
	}
	else if ( videoCodec == "xvid" )
	{
		if ( profile->muxer == "avi" )
		{
			args << "-ffourcc" << "XVID";
		}

		args << "-vf" << QString("scale=%1:%2,harddup")
								.arg(profile->video.rez.width()).arg(profile->video.rez.height());

		args << "-ovc" << "xvid";

		QStringList xvidencopts;

		if ( NPass > 1 )
		{
			xvidencopts << QString("pass=%1").arg(currentPass);
		}

		xvidencopts << QString("bitrate=%1").arg(profile->video.bitrate);

		if (settings->input.video.display_aspect > 1.31 && settings->input.video.display_aspect < 1.35)
		{
			xvidencopts << "aspect=4/3";

			if ( profile->muxer == "avi" ) args << "-force-avi-aspect" << "1.33";
		}
		else if (settings->input.video.display_aspect > 1.75 && settings->input.video.display_aspect < 1.79)
		{
			xvidencopts <<"aspect=16/9";

			if ( profile->muxer == "avi" ) args << "-force-avi-aspect" << "1.78";
		}
		else
		{
			xvidencopts << "autoaspect";
		}

		if ( profile->muxer != "mpeg" && profile->muxer != "avi" )  // so is lavf
		{
			xvidencopts << "max_bframes=1";  // no B-frames while lavf is broken
		}

		switch (profile->level)
		{
		case Video::Profile::Low:
			xvidencopts << "turbo" << "vhq=0" << "nohq_ac" << "notrellis" << "me_quality=4";
			break;
		case Video::Profile::Medium:
			xvidencopts << "vhq=1" << "nohq_ac";
			break;
		case Video::Profile::High:
			xvidencopts << "chroma_opt" << "vhq=4" << "hq_ac" << "trellis" << "me_quality=6";
			break;
		}

		// Ensure MPEG-4 profiles for full-compliance if not AVI
		if ( profile->muxer == "avi" )
		{
			if (profile->video.rez.width() <= 176 && profile->video.rez.height() <= 144)
			{
				xvidencopts << "profile=dxnhandheld";
			}
			else if (profile->video.rez.width() <= 352 && profile->video.rez.height() <= 288)
			{
				if (profile->standard == "NTSC")
				{
					xvidencopts << "profile=dxnportntsc";
				}
				else
				{
					xvidencopts << "profile=dxnportpal";
				}
			}
			else if (profile->video.rez.width() <= 352 && profile->video.rez.height() <= 576)
			{
				if (profile->standard == "NTSC")
				{
					xvidencopts << "profile=dxnhtntsc";
				}
				else
				{
					xvidencopts << "profile=dxnhtpal";
				}
			}
			else if (profile->video.rez.width() <= 1280 && profile->video.rez.height() <= 720)
			{
				xvidencopts << "profile=dxnhdtv";
			}
		}
		else
		{
			// Ensure MPEG-4 profiles for full-compliance if not AVI
			if (profile->video.rez.width() <= 176 && profile->video.rez.height() <= 144)
			{
				xvidencopts << "profile=asp1";
			}
			else if (profile->video.rez.width() <= 352 && profile->video.rez.height() <= 288)
			{
				xvidencopts << "profile=sp3";
			}
			else if (profile->video.rez.width() <= 352 && profile->video.rez.height() <= 576)
			{
				xvidencopts << "profile=asp4";
			}
			else if (profile->video.rez.width() <= 720 && profile->video.rez.height() <= 576)
			{
				xvidencopts << "profile=asp5";
			}
		}

		if ( !xvidencopts.isEmpty() )
		{
			args << "-xvidencopts" << xvidencopts.join(":");
		}
	}
	else if ( videoCodec == "x264" 
			|| videoCodec == "x264_lr" || videoCodec == "x264_hd"  
			|| videoCodec == "x264_psp" || videoCodec == "x264_divx")
	{
		args << "-vf" << QString("scale=%1:%2,harddup")
								.arg(profile->video.rez.width()).arg(profile->video.rez.height());

		args << "-ovc" << "x264";

		QStringList x264encopts;

		// DivX Plus HD
		if (videoCodec == "x264_divx")
		{
			x264encopts << QString("keyint=%1").arg( int(settings->input.video.fps * 4));
			x264encopts << "vbv_bufsize=25000";
			x264encopts << "vbv_maxrate=20000";
			x264encopts << "bframes=3";  // hope it works as expected even if lavf is broken
			x264encopts << "level_idc=40";
			x264encopts << "trellis=0";
			x264encopts << "nomixed_refs";
			x264encopts << "no8x8dct";
			x264encopts << "noweight_b";
			x264encopts << "weightp=0";
		}
		else if ( profile->muxer == "mov" || profile->muxer == "ipod" )
		{
			// QuickTime 7 requirements
			x264encopts << "bframes=1";
			x264encopts << "nob_adapt";
			x264encopts << "no8x8dct";
		}
		else if ( profile->muxer == "psp" )
		{
			x264encopts << "level_idc=30";
			x264encopts << "bframes=3";
			x264encopts << "weightp=0";
			x264encopts << "b_pyramid=0";
			x264encopts << "no8x8dct";
			x264encopts << "nocabac";
			x264encopts << "cqm=flat";
			x264encopts << "vbv_maxrate=2000";
			x264encopts << "vbv_bufsize=2000";
		}
		else if ( profile->muxer == "avi" )
		{
			x264encopts << "bframes=3";
		}
		else
		{
			//* experimental: broken LAVF
			x264encopts << "bframes=0";
		}

		if ( NPass > 1 )
		{
			x264encopts << QString("pass=%1").arg(currentPass);
		}

		x264encopts << QString("bitrate=%1").arg(profile->video.bitrate);


		if ( profile->muxer == "mov" )
		{
			x264encopts << QString("profile=main");
		}
		else if ( profile->muxer =="ipod"
			&& profile->video.rez.width() > 640 && profile->video.rez.height() > 480 ) 
		{
			x264encopts << QString("profile=main");			// iPod touch
		}
		else if ( profile->muxer =="ipod" ) 
		{
			x264encopts << QString("profile=baseline");		// iPod classic
		}
		else if ( profile->muxer =="psp" ) 
		{
			x264encopts << QString("profile=main");			// PSP
			//x264encopts << QString("level=3.0");			
		}
		else if ( profile->video.rez.height() < 240 )
		{
			x264encopts << QString("profile=baseline");		// Mobile
		}
		else if ( profile->video.rez.width() <= 720 && profile->video.rez.height() <= 480 )
		{
			x264encopts << QString("profile=main");			// Smartphone & Standard-Definition TV
		}
		else
		{
			x264encopts << QString("profile=high");			// HDTV & disc storage
		}

		if (profile->muxer != "mov" && profile->muxer != "ipod")
		{
			if (videoCodec == "x264_lr")
				x264encopts << QString("preset=medium");
			else if (videoCodec == "x264_hd" || videoCodec == "x264_divx")
				x264encopts << QString("preset=ultrafast");
			else
				x264encopts << QString("preset=fast");
		}
		else
		{
			//x264encopts << QString("preset=veryfast");
		}

		if ( !x264encopts.isEmpty() )
		{
			args << "-x264encopts" << x264encopts.join(":");
		}
	}
	else if ( videoCodec == "mpeg1video" )
	{
		QStringList vf;

		// We force 4:3 to be VCD compliant (the only relevant MPEG-1 usage)
		if(settings->input.video.display_aspect >= 1.35)
		{
			QSize rez(settings->input.video.scaledRez);
			rez.scale( profile->video.rez, Qt::KeepAspectRatio );

			int sarCorrection(rez.height());

			// Pixel Aspect Ratio correction for analog-to-digital conversion
			if (profile->standard == "PAL" 
				|| profile->video.rez.height() == 288 
				|| profile->video.rez.height() == 576)
			{
				sarCorrection = int((double)rez.height() * 12.0 / 11.0);
			}
			else
			{
				sarCorrection = int((double)rez.width() * 11.0 / 10.0);
			}
			rez.setHeight(sarCorrection);

			vf << QString("expand=%1:::::4/3").arg(profile->video.rez.width());
			vf << QString("scale=%1:%2").arg(profile->video.rez.width()).arg(profile->video.rez.height());
			vf << QString("harddup");
		}
		else
		{
			vf << QString("scale=%1:%2").arg(profile->video.rez.width()).arg(profile->video.rez.height());
			vf << QString("harddup");
		}
			
		if ( !vf.isEmpty() )
		{
			args << "-vf" << vf.join(",");
		}

		args << "-ovc" << "lavc";

		// VCD compliant
		lavcopts << QString("vcodec=%1").arg(videoCodec)
			<< "keyint=15" 
			<< "vrc_buf_size=327" 
			<< QString("vbitrate=%1").arg(profile->video.bitrate) 
			<< QString("vrc_minrate=%1").arg(profile->video.bitrate) 
			<< QString("vrc_maxrate=%1").arg(profile->video.bitrate) 
			<< "aspect=4/3";
	}
	else if ( videoCodec == "h263" )
	{
		QStringList vf;

		// H.263 is CIF/SIF 4:3 display
		if(settings->input.video.display_aspect >= 1.35)
		{
			QSize rez(settings->input.video.scaledRez);
			rez.scale( profile->video.rez, Qt::KeepAspectRatio );

			int sarCorrection(rez.height());

			// Pixel Aspect Ratio correction for analog-to-digital conversion
			if (profile->standard == "PAL" 
				|| profile->video.rez.height() == 288 
				|| profile->video.rez.height() == 576)
			{
				sarCorrection = int((double)rez.height() * 12.0 / 11.0);
			}
			else
			{
				sarCorrection = int((double)rez.width() * 11.0 / 10.0);
			}
			rez.setHeight(sarCorrection);

			vf << QString("expand=%1:::::4/3").arg(profile->video.rez.width());
			vf << QString("scale=%1:%2").arg(profile->video.rez.width()).arg(profile->video.rez.height());
			vf << QString("harddup");
		}
		else
		{
			vf << QString("scale=%1:%2").arg(profile->video.rez.width()).arg(profile->video.rez.height());
			vf << QString("harddup");
		}
			
		if ( !vf.isEmpty() )
		{
			args << "-vf" << vf.join(",");
		}

		args << "-ovc" << "lavc";

		lavcopts << QString("vcodec=%1").arg(videoCodec)
			<< "obmc" << "vqmin=8" << "aic" << "umv"
			<< QString("vbitrate=%1").arg(profile->video.bitrate);
	}
	else
	{
		// Codec name translations (synonyms)
		if ( videoCodec == "theora" )
		{
			videoCodec = "libtheora";
		}
		else if ( videoCodec == "xvid" )
		{
			videoCodec = "libxvid"; 
		}
		else if ( videoCodec == "x264" 
			|| videoCodec == "x264_lr" || videoCodec == "x264_hd"  || videoCodec == "x264_divx")
		
		{
			videoCodec = "libx264";
		}

		args << "-vf" << QString("scale=%1:%2,harddup")
								.arg(profile->video.rez.width()).arg(profile->video.rez.height());
			
		args << "-ovc" << "lavc";

		if ( videoCodec == "mpeg4"
			 && (profile->muxer == "mov" || profile->muxer == "ipod") )
		{
			// QuickTime 7 requirements (but not working in Mac QT player)
			lavcopts << QString("vcodec=%1").arg(videoCodec)
				<< QString("vbitrate=%1").arg(profile->video.bitrate)
				<< "keyint=300"
				<< "vb_strategy=0"
				<< "trell"
				<< "vmax_b_frames=1";	// should be exact B-Frames number
		}
		else if ( videoCodec == "mpeg2video" )
		{
			lavcopts << QString("vcodec=%1").arg(videoCodec)
				<< QString("vbitrate=%1").arg(profile->video.bitrate)
				<< "vmax_b_frames=0";	// no B-frames while lavf is broken

			if ( testFrames > 0 && testFrames <= 250 )
			{
				lavcopts << QString("keyint=%1").arg(testFrames - 1);  // 1st GOP must be complete
			}
		}
		else
		{
			lavcopts << QString("vcodec=%1").arg(videoCodec)
				<< QString("vbitrate=%1").arg(profile->video.bitrate)
				<< "vmax_b_frames=0";	// no B-frames while lavf is broken
		}

		if (settings->input.video.display_aspect > 1.31 && settings->input.video.display_aspect < 1.35)
		{
			lavcopts << "aspect=4/3";
		}
		else if (settings->input.video.display_aspect > 1.75 && settings->input.video.display_aspect < 1.79)
		{
			lavcopts << "aspect=16/9";
		}
		else
		{
			lavcopts << "autoaspect";
		}
	}

	// Audio
	QString audioCodec(profile->audio.codec);

	if ( audioCodec.isEmpty() || audioCodec == "noaudio" )
	{
		args << "-oac" << "null";
	}
	else if ( audioCodec == "mp3" || audioCodec == "mp3_lr"
			|| audioCodec == "mp3_flv" || audioCodec == "mp3_flv_lr" )
	{
		args << "-oac" << "mp3lame";

		if ( profile->audio.sampling > 0 )
			args << "-srate" << QString::number(profile->audio.sampling);

		QStringList audioFilters;
		
		if ( settings->output.audio.volume != 0 )
			audioFilters << QString("volume=%1").arg(settings->output.audio.volume);

		if ( profile->audio.sampling > 0 )
			audioFilters << QString("lavcresample=%1").arg(profile->audio.sampling);

		if ( !audioFilters.isEmpty() )
		{
			args << "-af" << audioFilters.join(":");
		}

		QStringList lameopts;

		lameopts << "mode=0";  // stereo

		if ( profile->audio.bitrate > 0.0 )
			lameopts << QString("cbr:br=%1").arg(int(profile->audio.bitrate));

		if ( !lameopts.isEmpty() )
		{
			args << "-lameopts" << lameopts.join(":");
		}
	}
#ifndef Q_OS_LINUX
	else if ( audioCodec == "aac" || audioCodec == "aac_lr" || audioCodec == "aac_hq"
			|| audioCodec == "aac_flv" )
	{
		args << "-oac" << "faac";

		if ( profile->audio.sampling > 0 )
			args << "-srate" << QString::number(profile->audio.sampling);

		QStringList audioFilters;
		
		if ( settings->output.audio.volume != 0 )
			audioFilters << QString("volume=%1").arg(settings->output.audio.volume);

		if ( profile->audio.sampling > 0 )
			audioFilters << QString("lavcresample=%1").arg(profile->audio.sampling);

		if ( !audioFilters.isEmpty() )
		{
			args << "-af" << audioFilters.join(":");
		}

		QStringList faacopts;

		if ( profile->muxer == "ipod" || profile->muxer == "m4a" )
		{
			faacopts << "raw";  // avoid error: [ipod @ 0195EBC0] malformated aac bitstream, use -absf aac_adtstoasc
		}
		
		if ( profile->audio.bitrate > 0.0 )
			faacopts << QString("br=%1").arg(int(profile->audio.bitrate));

		if ( !faacopts.isEmpty() )
		{
			args << "-faacopts" << faacopts.join(":");
		}
	}
#endif
	else if ( audioCodec == "ac3" || audioCodec == "ac3_copy" )
	{
		args << "-oac" << "copy";
	}
	else
	{
		if ( profile->audio.sampling > 0 )
			args << "-srate" << QString::number(profile->audio.sampling);

		args << "-oac" << "lavc";
		
		QStringList audioFilters;
		
		if ( audioCodec == "amrnb" )
		{
			audioFilters << "pan=1:0.5:0.5";  // stereo to mono downmix (mono only for libopencore_amrnb)
		}
		else if ( audioCodec == "pcm" && profile->audio.bitrate < 1536 )
		{
			audioFilters << "pan=1:0.5:0.5";  // stereo to mono downmix
		}
		else if ( audioCodec == "pcm" && settings->input.audio.channel_number > 2)
		{
			audioFilters << "pan=2:.32:.32:.39:.06:.06:.39:.17:-.17:-.17:.17:.33:.33";  // 5.1 downmix (PCM compliance)
		}
		else if ( audioCodec == "ac3" /*&& profile->audio.bitrate <= 256*/
				&& settings->input.audio.channel_number > 2 )
		{
			audioFilters << "pan=2:.32:.32:.39:.06:.06:.39:.17:-.17:-.17:.17:.33:.33";  // 5.1 downmix (PCM compliance)
		}

		if ( settings->output.audio.volume != 0 )
			audioFilters << QString("volume=%1").arg(settings->output.audio.volume);

		if ( profile->audio.sampling > 0 )
			audioFilters << QString("lavcresample=%1").arg(profile->audio.sampling);

		if ( !audioFilters.isEmpty() )
		{
			args << "-af" << audioFilters.join(":");
		}

		// Codec name translations (synonyms); vorbis must NOT be translated to libvorbis
		if ( audioCodec == "aac" || audioCodec == "aac_lr" || audioCodec == "aac_hq"
			|| audioCodec == "aac_flv" )
		{
#ifdef Q_OS_LINUX
			audioCodec = "aac";
#else
			audioCodec = "libfaac";
#endif
		}
		else if ( audioCodec == "amrnb" )
		{
			audioCodec = "libopencore_amrnb";
		}
		else if ( audioCodec == "mp2_vcd" )
		{
			audioCodec = "mp2";
		}
		else if ( audioCodec == "pcm" && (profile->muxer == "au" || profile->muxer == "mpeg") )
		{
			audioCodec = "pcm_s16be";
		}
		else if ( audioCodec == "pcm" )
		{
			audioCodec = "pcm_s16le";
		}
		else if ( audioCodec == "vorbis" )
		{
			audioCodec = "libvorbis";
		}

		if (profile->audio.bitrate > 0.0 && audioCodec!="flac") 
			lavcopts << QString("abitrate=%1").arg(int(profile->audio.bitrate));
		
		lavcopts << QString("acodec=%1").arg(audioCodec);
	}
	
	if ( !lavcopts.isEmpty() )
	{
		args << "-lavcopts" << lavcopts.join(":");
	}

	args << "-o" << target;

	return args;
}

void InterfaceMEncoder::cliCmdEncode(QString *cmd, QStringList *args, const QString &output,
	int testFrames, int testChapter, int seekPosition)
{
	QString target(output);

	cmd->clear();
	args->clear();

	// Command
	*cmd = exec.toLatin1();

	// Profile set?
	if ( settings->output.profile.level != Video::Profile::None
		&& settings->output.profile.level != Video::Profile::User ) 
	{
		*args = profileCommandLine(&settings->output.profile, output, testFrames, testChapter, seekPosition);

		qDebug() << "InterfaceMEncoder::cliCmdEncode() returns command:" << *cmd << "with options" << *args;	
		return;
	}

	QStringList lavcopts;

	// Input
	if ( settings->input.source.media == Video::Media::DVD )
	{
		int title = settings->input.video.title;
		int audioId = settings->input.audio.aid;
		QString audioLang = settings->input.audio.language;
		int subtitleId = settings->input.subtitle.sid;
		QString subtitleLang = settings->input.subtitle.language;
	
		// DVD
		*args << "-dvd-device" << settings->input.source.path;
		*args << QString("dvd://%1").arg(QString::number(title));

		if (audioId > -1)
		{
			*args << "-aid" << QString::number(audioId);
		}
		else if (!audioLang.isEmpty() && audioLang != "en")
		{
			*args << "-alang" << QString("%1,en").arg(audioLang);
		}
		else
		{
			*args << "-alang" << "en";
		}

		if (subtitleId > -1)
		{
			*args << "-sid" << QString::number(subtitleId);
		}
		else if (!subtitleLang.isEmpty() && subtitleLang != "en")
		{
			*args << "-slang" << QString("%1,en").arg(subtitleLang);
		}
		else if (!subtitleLang.isEmpty())
		{
			*args << "-slang" << "en";
		}
		else
		{
			*args << "-nosub";
		}
		
		if (!settings->input.no_video && settings->input.video.angle > 1)
			*args << "-dvdangle" << QString::number(settings->input.video.angle);

		if ( testChapter > 0 )
		{
			*args << "-chapter" << QString::number(testChapter);
		}
	}
	else
	{
		// File
		*args << settings->input.source.path;

		if (!settings->input.no_audio && settings->input.audio.n > -1)
			*args << "-aid" << QString::number(settings->input.audio.aid);

		if (!settings->input.no_subtitle && settings->input.subtitle.n > -1)
			*args << "-sid" << QString::number(settings->input.subtitle.sid);

		if ( seekPosition > 0 )
		{
			*args << "-ss" << QString::number(seekPosition);
		}
	}

	// Testing mode
	if ( testFrames > 0 )
	{
		*args << "-frames" << QString::number(testFrames);
	}

	// Encoder options
	*args << "-noskip";  // for A/V synchro

	QMapIterator<QString, QString> optionIterator(settings->output.options);
	while (optionIterator.hasNext())
	{
		optionIterator.next();
		if (optionIterator.value().isEmpty())
			*args << optionIterator.key();
		else
			*args << optionIterator.key() << optionIterator.value();
	}

	// Muxer
	if ( settings->output.muxer == "avi" )
	{
		*args << "-of" << "avi";
	}
	else if ( settings->output.muxer == "mp3" || settings->output.muxer == "ac3" 
			|| settings->output.muxer == "au" || settings->output.muxer == "wav"
			|| settings->output.muxer == "m4a" )
	{
		QFileInfo fi(output);
		target = fi.path() + "/" + fi.completeBaseName() + " (step 0).avi";

		*args << "-of" << "avi"; // audio have to be remuxed from avi to mp3/ac3/au/wav with FFmpeg
	}
	else if ( settings->output.muxer == "mpeg" || settings->output.muxer == "mpeg_vcd" )
	{
		*args << "-of" << "mpeg";

		QStringList mpegopts;

		if ( settings->output.video.codec == "mpeg1video" ) 
		{
			mpegopts << "format=xvcd";
		}
		else if ( settings->output.video.codec == "mpeg2video" 
			&& settings->output.video.rez.width() < 704  ) 
		{
			mpegopts << "format=xsvcd";
		}
		else if ( settings->output.video.codec == "mpeg2video" ) 
		{
			mpegopts << "format=dvd";
		}

		if (settings->output.video.standard == "PAL")
		{
			*args << "-ofps" << "25";
		}
		else if (settings->output.video.standard == "NTSC")
		{
			if (settings->input.video.fps < 29.0)
			{
				*args << "-ofps" << "24000/1001";
			}
			else
			{
				*args << "-ofps" << "30000/1001";
			}
		}

		if ( !mpegopts.isEmpty() )
		{
			*args << "-mpegopts" << mpegopts.join(":");
		}
	}
	else
	{
		// Force fps (required at least for mpeg1video, asf and some mov)
		if (settings->output.muxer == "asf" || settings->output.muxer == "mov" 
			|| settings->output.muxer == "qt") 
		{
			if (settings->output.video.standard == "PAL")
			{
				*args << "-ofps" << "25";
			}
			else if (settings->output.video.standard == "NTSC")
			{
				if (settings->input.video.fps < 29.0)
				{
					*args << "-ofps" << "24000/1001";
				}
				else
				{
					*args << "-ofps" << "30000/1001";
				}
			}
			else
			{
				*args << "-ofps" << QString::number(settings->input.video.fps);
			}
		}

		// lavf muxer
		*args << "-of" << "lavf";

		QString format(settings->output.muxer);

		if (settings->output.muxer == "mov")
		{
			format = "qt";
		}
		*args << "-lavfopts" << QString("format=%1").arg(format);	
	}

	// Video
	QString videoCodec(settings->output.video.codec);

	if ( videoCodec.isEmpty() || videoCodec == "novideo" )
	{
		*args << "-ovc" << "frameno";
	}
	else if ( videoCodec == "xvid" )
	{
		if ( settings->output.muxer == "avi" )
		{
			*args << "-ffourcc" << "XVID";
		}

		*args << "-vf" << QString("scale=%1:%2,harddup")
								.arg(settings->output.video.rez.width())
								.arg(settings->output.video.rez.height());

		*args << "-ovc" << "xvid";

		QStringList xvidencopts;

		if ( NPass > 1 )
		{
			if ( currentPass < NPass ) xvidencopts << "turbo";

			xvidencopts << QString("pass=%1").arg(currentPass);
		}

		xvidencopts << QString("bitrate=%1").arg(settings->output.video.bitrate);

		if (settings->input.video.display_aspect > 1.31 && settings->input.video.display_aspect < 1.35)
		{
			xvidencopts << "aspect=4/3";
		}
		else if (settings->input.video.display_aspect > 1.75 && settings->input.video.display_aspect < 1.79)
		{
			xvidencopts <<"aspect=16/9";

			if ( settings->output.muxer == "avi" ) *args << "-force-avi-aspect" << "1.78";
		}
		else
		{
			xvidencopts << "autoaspect";
		}

		if ( settings->output.muxer != "mpeg" && settings->output.muxer != "avi" )  // so is lavf
		{
			xvidencopts << "max_bframes=1";  // no B-frames while lavf is broken
		}

		if ( !settings->output.video.profile.isEmpty() )
		{
			xvidencopts << QString("profile=%1").arg(settings->output.video.profile);
		}
		else if ( settings->output.muxer == "avi" )
		{
			if (settings->output.video.rez.width() <= 176 && settings->output.video.rez.height() <= 144)
			{
				xvidencopts << "profile=dxnhandheld";
			}
			else if (settings->output.video.rez.width() <= 352 && settings->output.video.rez.height() <= 288)
			{
				if (settings->output.video.standard == "NTSC")
				{
					xvidencopts << "profile=dxnportntsc";
				}
				else
				{
					xvidencopts << "profile=dxnportpal";
				}
			}
			else if (settings->output.video.rez.width() <= 352 && settings->output.video.rez.height() <= 576)
			{
				if (settings->output.video.standard == "NTSC")
				{
					xvidencopts << "profile=dxnhtntsc";
				}
				else
				{
					xvidencopts << "profile=dxnhtpal";
				}
			}
			else if (settings->output.video.rez.width() <= 1280 && settings->output.video.rez.height() <= 720)
			{
				xvidencopts << "profile=dxnhdtv";
			}
		}
		else
		{
			// Ensure MPEG-4 profiles for full-compliance if not AVI
			if (settings->output.video.rez.width() <= 176 && settings->output.video.rez.height() <= 144)
			{
				xvidencopts << "profile=asp1";
			}
			else if (settings->output.video.rez.width() <= 352 && settings->output.video.rez.height() <= 288)
			{
				xvidencopts << "profile=sp3";
			}
			else if (settings->output.video.rez.width() <= 352 && settings->output.video.rez.height() <= 576)
			{
				xvidencopts << "profile=asp4";
			}
			else if (settings->output.video.rez.width() <= 720 && settings->output.video.rez.height() <= 576)
			{
				xvidencopts << "profile=asp5";
			}
		}

		if ( !xvidencopts.isEmpty() )
		{
			*args << "-xvidencopts" << xvidencopts.join(":");
		}
	}
	else if ( videoCodec == "x264" 
			|| videoCodec == "x264_lr" || videoCodec == "x264_hd"
			|| videoCodec == "x264_psp" || videoCodec == "x264_divx")
	{
		*args << "-vf" << QString("scale=%1:%2,harddup")
								.arg(settings->output.video.rez.width())
								.arg(settings->output.video.rez.height());

		*args << "-ovc" << "x264";

		QStringList x264encopts;

		x264encopts << QString("bitrate=%1").arg(settings->output.video.bitrate);

		// DivX Plus HD
		if (videoCodec == "x264_divx")
		{
			x264encopts << QString("keyint=%1").arg( int(settings->input.video.fps * 4));
			x264encopts << "vbv_bufsize=25000";
			x264encopts << "vbv_maxrate=20000";
			x264encopts << "bframes=3";  // hope it works as expected even if lavf is broken
			x264encopts << "level_idc=40";
			x264encopts << "trellis=0";
			x264encopts << "nomixed_refs";
			x264encopts << "no8x8dct";
			x264encopts << "noweight_b";
			x264encopts << "weightp=0";
		}
		else if ( settings->output.muxer == "mov" || settings->output.muxer == "ipod" )
		{
			// QuickTime 7 requirements
			x264encopts << "bframes=1";
			x264encopts << "nob_adapt";
			x264encopts << "no8x8dct";
		}
		else if ( settings->output.muxer == "psp" )
		{
			x264encopts << "level_idc=30";
			x264encopts << "bframes=3";
			x264encopts << "weightp=0";
			x264encopts << "b_pyramid=0";
			x264encopts << "no8x8dct";
			x264encopts << "nocabac";
			x264encopts << "cqm=flat";
			x264encopts << "vbv_maxrate=2000";
			x264encopts << "vbv_bufsize=2000";
		}
		else if ( settings->output.muxer == "avi" )
		{
			x264encopts << "bframes=3";
		}
		else
		{
			//* experimental: broken LAVF
			x264encopts << "bframes=0";
		}

		if ( NPass > 1 )
		{
			x264encopts << QString("pass=%1").arg(currentPass);
		}

		QString profile( settings->output.video.profile.mid(5) ); // remove x264_ from profile name

		if ( profile.isEmpty() )
		{		
			if ( settings->output.muxer =="mov" )
			{
				x264encopts << QString("profile=main");
			}
			else if ( settings->output.muxer =="ipod"
				&& settings->output.video.rez.width() >  640 && settings->output.video.rez.height() > 480 ) 
			{
				x264encopts << QString("profile=main");			// iPod touch
			}
			else if ( settings->output.muxer =="ipod" ) 
			{
				x264encopts << QString("profile=baseline");		// iPod classic
			}
			else if ( settings->output.muxer =="psp" ) 
			{
				x264encopts << QString("profile=main");			// PSP
				//x264encopts << QString("level=3.0");			
			}
			else if ( settings->output.video.rez.height() < 240 )
			{
				x264encopts << QString("profile=baseline");		// Mobile
			}
			else if ( settings->output.video.rez.width() <= 720 && settings->output.video.rez.height() <= 480 )
			{
				x264encopts << QString("profile=main");			// Smartphone & Standard-Definition TV
			}
			else
			{
				x264encopts << QString("profile=high");			// HDTV & disc storage
			}
		}
		else
		{
			x264encopts << QString("profile=%1").arg(profile);
		}

		if (settings->output.muxer != "mov" && settings->output.muxer != "ipod")
		{

			if ( settings->output.video.preset.isEmpty() )
			{
				if (videoCodec == "x264_lr")
					x264encopts << QString("preset=medium");
				else if (videoCodec == "x264_hd" || videoCodec == "x264_divx")
					x264encopts << QString("preset=ultrafast");
				else
					x264encopts << QString("preset=fast");
			}
			else
			{
				x264encopts << QString("preset=%1").arg(settings->output.video.preset);
			}
		}

		if ( !x264encopts.isEmpty() )
		{
			*args << "-x264encopts" << x264encopts.join(":");
		}
	}
	else if ( videoCodec == "mpeg1video" )
	{
		QStringList vf;

		if(settings->input.video.display_aspect >= 1.35)
		{
			QSize rez(settings->input.video.scaledRez);
			rez.scale( settings->output.video.rez, Qt::KeepAspectRatio );

			int sarCorrection(rez.height());

			// Pixel Aspect Ratio correction for analog-to-digital conversion
			if (settings->output.video.standard == "PAL" 
				|| settings->output.video.rez.height() == 288 
				|| settings->output.video.rez.height() == 576)
			{
				sarCorrection = int((double)rez.height() * 12.0 / 11.0);
			}
			else
			{
				sarCorrection = int((double)rez.width() * 11.0 / 10.0);
			}
			rez.setHeight(sarCorrection);

			vf << QString("expand=%1:::::4/3").arg(settings->output.video.rez.width());
			vf << QString("scale=%1:%2").arg(settings->output.video.rez.width()).arg(settings->output.video.rez.height());
			vf << QString("harddup");
		}
		else
		{
			vf << QString("scale=%1:%2").arg(settings->output.video.rez.width()).arg(settings->output.video.rez.height());
			vf << QString("harddup");
		}
			
		if ( !vf.isEmpty() )
		{
			*args << "-vf" << vf.join(",");
		}

		*args << "-ovc" << "lavc";

		// VCD compliant
		lavcopts << QString("vcodec=%1").arg(videoCodec)
			<< "keyint=15" 
			<< "vrc_buf_size=327" 
			<< QString("vbitrate=%1").arg(settings->output.video.bitrate) 
			<< QString("vrc_minrate=%1").arg(settings->output.video.bitrate) 
			<< QString("vrc_maxrate=%1").arg(settings->output.video.bitrate) 
			<< "aspect=4/3";
			
		*args << "-ovc" << "lavc";

		lavcopts << QString("vcodec=%1").arg(videoCodec)
			<< QString("vbitrate=%1").arg(settings->output.video.bitrate) << "idct=0";
	}
	else if ( videoCodec == "h263" )
	{
		QStringList vf;

		// H.263 is CIF/SIF 4:3 display
		if(settings->input.video.display_aspect >= 1.35)
		{
			QSize rez(settings->input.video.scaledRez);
			rez.scale( settings->output.video.rez, Qt::KeepAspectRatio );

			int sarCorrection(rez.height());

			// Pixel Aspect Ratio correction for analog-to-digital conversion
			if (settings->output.video.standard == "PAL" 
				|| settings->output.video.rez.height() == 288 
				|| settings->output.video.rez.height() == 576)
			{
				sarCorrection = int((double)rez.height() * 12.0 / 11.0);
			}
			else
			{
				sarCorrection = int((double)rez.width() * 11.0 / 10.0);
			}
			rez.setHeight(sarCorrection);

			vf << QString("expand=%1:::::4/3").arg(settings->output.video.rez.width());
			vf << QString("scale=%1:%2").arg(settings->output.video.rez.width()).arg(settings->output.video.rez.height());
			vf << QString("harddup");
		}
		else
		{
			vf << QString("scale=%1:%2").arg(settings->output.video.rez.width()).arg(settings->output.video.rez.height());
			vf << QString("harddup");
		}
			
		if ( !vf.isEmpty() )
		{
			*args << "-vf" << vf.join(",");
		}

		*args << "-ovc" << "lavc";

		lavcopts << QString("vcodec=%1").arg(videoCodec)
			<< "obmc" << "vqmin=8" << "aic" << "umv"
			<< QString("vbitrate=%1").arg(settings->output.video.bitrate);
	}
	else
	{
		// Codec name translations (synonyms)
		if ( videoCodec == "theora" )
		{
			videoCodec = "libtheora";  // not sure we've to translate theora
		}
		else if ( videoCodec == "xvid" )
		{
			videoCodec = "libxvid"; 
		}
		else if ( videoCodec == "x264" 
			|| videoCodec == "x264_lr" || videoCodec == "x264_hd"  || videoCodec == "x264_divx")
		
		{
			videoCodec = "libx264";
		}

		*args << "-vf" << QString("scale=%1:%2,harddup")
								.arg(settings->output.video.rez.width())
								.arg(settings->output.video.rez.height());		
	
		*args << "-ovc" << "lavc";
		
		if ( videoCodec == "mpeg4"
			 && (settings->output.muxer == "mov" || settings->output.muxer == "ipod") )
		{
			// QuickTime 7 requirements (but not working in Mac QT player)
			lavcopts << QString("vcodec=%1").arg(videoCodec)
				<< QString("vbitrate=%1").arg(settings->output.video.bitrate)
				<< "keyint=300"
				<< "vb_strategy=0"
				<< "trell"
				<< "vmax_b_frames=1";	// should be exact B-Frames number
		}
		else if ( videoCodec == "mpeg2video" )
		{
			lavcopts << QString("vcodec=%1").arg(videoCodec)
				<< QString("vbitrate=%1").arg(settings->output.video.bitrate)
				<< "vmax_b_frames=0";	// no B-frames while lavf is broken

			if ( testFrames > 0 && testFrames <= 250 )
			{
				lavcopts << QString("keyint=%1").arg(testFrames - 1);  // 1st GOP must be complete
			}
		}
		else
		{
			lavcopts << QString("vcodec=%1").arg(videoCodec)
				<< QString("vbitrate=%1").arg(settings->output.video.bitrate)
				<< "vmax_b_frames=0";	// no B-frames while lavf is broken
		}

		if (settings->input.video.display_aspect > 1.31 && settings->input.video.display_aspect < 1.35)
		{
			lavcopts << "aspect=4/3";
		}
		else if (settings->input.video.display_aspect > 1.75 && settings->input.video.display_aspect < 1.79)
		{
			lavcopts <<"aspect=16/9";
		}
		else
		{
			lavcopts << "autoaspect";
		}
	}

	// Audio
	QString audioCodec(settings->output.audio.codec);

	if ( audioCodec.isEmpty() || audioCodec == "noaudio" )
	{
		*args << "-oac" << "null";
	}
	else if ( audioCodec == "mp3" || audioCodec == "mp3_lr"
			|| audioCodec == "mp3_flv" || audioCodec == "mp3_flv_lr" )
	{
		*args << "-oac" << "mp3lame";

		if ( settings->output.audio.sampling > 0 )
			*args << "-srate" << QString::number(settings->output.audio.sampling);

		QStringList audioFilters;
		
		if ( settings->output.audio.volume != 0 )
			audioFilters << QString("volume=%1").arg(settings->output.audio.volume);

		if ( settings->output.audio.sampling > 0 )
			audioFilters << QString("lavcresample=%1").arg(settings->output.audio.sampling);

		if ( !audioFilters.isEmpty() )
		{
			*args << "-af" << audioFilters.join(":");
		}

		QStringList lameopts;

		lameopts << "mode=0";  // stereo

		if ( settings->output.audio.kbps > 0.0 )
			lameopts << QString("cbr:br=%1").arg(int(settings->output.audio.kbps));

		if ( !lameopts.isEmpty() )
		{
			*args << "-lameopts" << lameopts.join(":");
		}
	}
	// MEncoder linux has no libfaac capability (so use lavc)
#ifndef Q_OS_LINUX
	else if ( audioCodec == "aac" || audioCodec == "aac_lr" || audioCodec == "aac_hq"
			|| audioCodec == "aac_flv" )
	{
		*args << "-oac" << "faac";

		if ( settings->output.audio.sampling > 0 )
			*args << "-srate" << QString::number(settings->output.audio.sampling);

		QStringList audioFilters;
		
		if ( settings->output.audio.volume != 0 )
			audioFilters << QString("volume=%1").arg(settings->output.audio.volume);

		if ( settings->output.audio.sampling > 0 )
			audioFilters << QString("lavcresample=%1").arg(settings->output.audio.sampling);

		if ( !audioFilters.isEmpty() )
		{
			*args << "-af" << audioFilters.join(":");
		}

		QStringList faacopts;

		if ( settings->output.audio.kbps > 0.0 )
			faacopts << QString("br=%1").arg(int(settings->output.audio.kbps));

		if ( settings->output.muxer == "ipod" || settings->output.muxer == "m4a" )
		{
			faacopts << "raw";  // avoid error: [ipod @ 0195EBC0] malformated aac bitstream, use -absf aac_adtstoasc
		}

		if ( !faacopts.isEmpty() )
		{
			*args << "-faacopts" << faacopts.join(":");
		}
	}
#endif
	else if ( audioCodec == "ac3" || audioCodec == "ac3_copy" )
	{
		*args << "-oac" << "copy";
	}
	else
	{
		if ( settings->output.audio.sampling > 0 )
			*args << "-srate" << QString::number(settings->output.audio.sampling);

		*args << "-oac" << "lavc";

		QStringList audioFilters;

		if ( audioCodec == "libopencore_amrnb" )
		{
			audioFilters << "pan=1:0.5:0.5";  // stereo to mono downmix (mono only for AMR-NB)
		}
		else if ( audioCodec == "pcm" && settings->output.audio.kbps < 1536 )
		{
			audioFilters << "pan=1:0.5:0.5";  // stereo to mono downmix (PCM compliance)
		}
		else if ( audioCodec == "pcm" && settings->input.audio.channel_number > 2 )
		{
			audioFilters << "pan=2:.32:.32:.39:.06:.06:.39:.17:-.17:-.17:.17:.33:.33";  // 5.1 downmix (PCM compliance)
		}
		else if ( audioCodec == "ac3" 
				&& settings->input.audio.channel_number > 2 )
		{
			audioFilters << "pan=2:.32:.32:.39:.06:.06:.39:.17:-.17:-.17:.17:.33:.33";  // 5.1 downmix (PCM compliance)
		}
		if ( settings->output.audio.volume != 0 )
			audioFilters << QString("volume=%1").arg(settings->output.audio.volume);

		if ( settings->output.audio.sampling > 0 )
			audioFilters << QString("lavcresample=%1").arg(settings->output.audio.sampling);

		if ( !audioFilters.isEmpty() )
		{
			*args << "-af" << audioFilters.join(":");
		}

		// Codec name translations (synonyms); vorbis must NOT be translated to libvorbis
		if ( audioCodec == "aac" || audioCodec == "aac_lr" || audioCodec == "aac_hq"
			|| audioCodec == "aac_flv" )
		{		
#ifdef Q_OS_LINUX
			audioCodec = "aac";
#else
			audioCodec = "libfaac";
#endif
		}
		else if ( audioCodec == "amrnb" )
		{
			audioCodec = "libopencore_amrnb";
		}
		else if ( audioCodec == "mp2_vcd" )
		{
			audioCodec = "mp2";
		}
		else if ( audioCodec == "pcm" && (settings->output.muxer == "au" || settings->output.muxer == "mpeg") )
		{
			audioCodec = "pcm_s16be";
		}
		else if ( audioCodec == "pcm" )
		{
			audioCodec = "pcm_s16le";
		}
		else if ( audioCodec == "vorbis" )
		{
			audioCodec = "libvorbis";
		}

		if (settings->output.audio.kbps > 0.0 && audioCodec!="flac") 
			lavcopts << QString("abitrate=%1").arg(int(settings->output.audio.kbps));
		
		lavcopts << QString("acodec=%1").arg(audioCodec);
	}

	if ( !lavcopts.isEmpty() )
	{
		*args << "-lavcopts" << lavcopts.join(":");
	}

	*args << "-o" << target;
	
	qDebug() << "InterfaceMEncoder::cliCmdEncode() returns command:" << *cmd << "with options" << *args;	
}

void InterfaceMEncoder::cliCmdRemux(const QString &in, const QString &out,
		QString *cmd, QStringList *args, const QString &muxer)
{
	cmd->clear();
	args->clear();

	// Command
	*cmd = exec.toLatin1();

	*args << in << "-ovc" << "copy" << "-oac" << "copy";

	if (muxer == "avi")
	{
		*args << "-of" << "avi";
	}
	else if (muxer == "mpeg")
	{
		*args << "-of" << "mpeg" << "-mpegopts" << "interleaving2";
	}
	else if (muxer == "mkv")
	{
		*args << "-of" << "lavf" << "-lavfopts" << "format=matroska";
	}
	else
	{
		*args << "-of" << "lavf" << "-lavfopts" << QString("format=%1").arg(muxer);
	}

	*args << "-o" << out;

	qDebug() << "InterfaceMEncoder::cliCmdRemux() returns command:" << *cmd << "with options" << *args;
}

void InterfaceMEncoder::cliCmdGetStatus(QString *cmd, QStringList *args)
{
	cmd->clear();
	args->clear();

	// Command
	*cmd = exec.toLatin1();

	// Query video and audio supported
	*args << "-ovc" << "help" << "-oac" << "help" << "-of" << "help";

	qDebug() << "InterfaceMEncoder::cliCmdGetStatus() returns command:" << *cmd << "with options" << *args;
}

void InterfaceMEncoder::parseStatus()
{
	qDebug() << "InterfaceMEncoder::parseStatus() starts parsing status raw data";

	if (status->state != Video::Status::RawStatus) 
	{
		status->state = Video::Status::ParseFail;
		return;
	}

	// Parse standard output

	QRegExp rx(RX_CATCH_MENCODER_OUTPUT_STATUS);
	rx.setCaseSensitivity(Qt::CaseInsensitive);
	rx.setMinimal(true);
	rx.indexIn(status->cout);
	if (rx.numCaptures() != 1 || rx.cap(1).length() == 0)
	{
		qDebug("InterfaceMEncoder::parseStatus() - Failed to parse MEncoder standard output (signature)");
		status->state = Video::Status::ParseFail;
		return;
	}
	QString signature = rx.cap(1);
	qDebug() << "InterfaceMEncoder::parseStatus() - signature:" << signature;

	rx.setPattern(RX_PARSE_MENCODER_SIGNATURE);
	rx.setMinimal(true);
	rx.indexIn(signature);
	if (rx.numCaptures() != 3 || rx.cap(1).length() == 0 || rx.cap(2).length() == 0)
	{
		qDebug("InterfaceMEncoder::parseStatus() - Failed to parse MEncoder standard output (parsing signature)");
		status->state = Video::Status::ParseFail;
		return;
	}
	status->encoder = rx.cap(1);
	status->version = rx.cap(2);

	rx.setPattern(RX_CATCH_MENCODER_OUTPUT_HELP);
	rx.setMinimal(false);
	rx.indexIn(status->cout);
	if (rx.numCaptures() != 3)
	{
		qDebug("InterfaceMEncoder::parseStatus() - Failed to parse MEncoder standard output (-ovc help -oac help)");
		status->state = Video::Status::ParseFail;
		return;
	}
	QString videocodecs = rx.cap(1);
	QString audiocodecs = rx.cap(2);
	QString outputformats = rx.cap(3);
	qDebug() << "InterfaceMEncoder::parseStatus() - available video:" << videocodecs;
	qDebug() << "InterfaceMEncoder::parseStatus() - available audio:" << audiocodecs;
	qDebug() << "InterfaceMEncoder::parseStatus() - available muxer:" << outputformats;

	// Parse codecs, audio codecs and formats
	rx.setPattern(RX_PARSE_MENCODER_VAF_HELP);
	rx.setCaseSensitivity(Qt::CaseSensitive);
	rx.setMinimal(false);

	// Video codecs
	capability->video->clear();
	int pos(0);
	while ((pos = rx.indexIn(videocodecs, pos)) != -1) 
	{
		if ( videos->contains( rx.cap(1) ) )
		{
			capability->video->insert( rx.cap(1), rx.cap(2) );
	
			qDebug() << "InterfaceMEncoder::parseStatus() - found video codec available:" << rx.cap(1) << rx.cap(2);

			if ( rx.cap(1) == "lavc" )
			{
				// Add a list of supported video libavcodec's
				capability->libVideo->insert( "lavc", libffSupport["video"] ); 

				qDebug() << "InterfaceMEncoder::parseStatus() - added lavc-video codecs:" << libffSupport["video"];
			}
		}
		else
		{
			qDebug() << "InterfaceMEncoder::parseStatus() - ignore video codec available (not supported):" << rx.cap(1) << rx.cap(2);
		}

		pos += rx.matchedLength();
	}

	// Audio codecs
	capability->audio->clear();
	pos = 0;
	while ((pos = rx.indexIn(audiocodecs, pos)) != -1) 
	{
		if ( audios->contains( rx.cap(1) ) )
		{
			capability->audio->insert( rx.cap(1), rx.cap(2) ); 

			qDebug() << "InterfaceMEncoder::parseStatus() - found audio codec available:" << rx.cap(1) << rx.cap(2);

			if ( rx.cap(1) == "lavc" )
			{
				// Add a list of supported audio libavcodec's
				capability->libAudio->insert( "lavc", libffSupport["audio"] ); 

				qDebug() << "InterfaceMEncoder::parseStatus() - added lavc-audio codecs:" << libffSupport["lavc"];
			}
		}
		else
		{
			qDebug() << "InterfaceMEncoder::parseStatus() - ignore audio codec available (not supported):" << rx.cap(1) << rx.cap(2);
		}

		pos += rx.matchedLength();
	}

	// Subtitle codecs, none supported yet
	capability->subtitle->clear();

	// Muxers
	capability->muxer->clear();
	pos = 0;
	while ((pos = rx.indexIn(outputformats, pos)) != -1) 
	{
		if ( muxers->contains( rx.cap(1) ) )
		{
			capability->muxer->insert( rx.cap(1), rx.cap(2) ); 

			qDebug() << "InterfaceMEncoder::parseStatus() - found muxer format available:" << rx.cap(1) << rx.cap(2);

			if ( rx.cap(1) == "lavf" )
			{
				// Add a list of supported muxer libavformat's
				capability->libMuxer->insert( "lavf", libffSupport["muxer"] ); 

				qDebug() << "InterfaceMEncoder::parseStatus() - added lavf-format muxers:" << libffSupport["muxer"];
			}
		}
		else
		{
			qDebug() << "InterfaceMEncoder::parseStatus() - ignore muxer format available (not supported):" << rx.cap(1) << rx.cap(2);
		}

		pos += rx.matchedLength();
	}

	status->state = Video::Status::EngineOk;
}

bool InterfaceMEncoder::parseCommandCheck( QByteArray *cout, QByteArray *cerr )
{
	qDebug() << "InterfaceMEncoder::parseCommandCheck() starts parsing standard output";

	QRegExp rx(RX_PARSE_MENCODER_OUTPUT_VALID);
	rx.setCaseSensitivity(Qt::CaseInsensitive);
	rx.setMinimal(true);
	rx.indexIn(*cout);

	return (rx.numCaptures() == 4) && (rx.cap(1).length() > 0);
}

bool InterfaceMEncoder::parseOutput(QString *output, QString *warning, 
	int *frame, double *time, int *percent, int *remain, double *speed, int *size)
{
	QRegExp rx("([^\\r]+)\\r");
	rx.setCaseSensitivity(Qt::CaseSensitive);
	rx.setMinimal(true);

	int pos = 0;
	QString str, warn;

	while ((pos = rx.indexIn(*output, pos)) != -1) 
	{
		//qDebug() << pos << "CAPTURES=" << rx.numCaptures() << rx.capturedTexts();
		
		QString cap = rx.cap(1);

		if ( cap.length() > 0 )
		{
			if ( cap.startsWith("Pos:") )
			{
				str = cap;
			}
			else //if ( !cap.isEmpty() )
			{
				warn.append( cap );
			}
		}
		pos += rx.matchedLength();
	}

	if ( str.isEmpty() && warn.isEmpty() ) return false;

	rx.setPattern(RX_PARSE_MENCODER_PROGRESS);
	rx.setMinimal(false);
	rx.indexIn(str);
	
	//qDebug() << "CAPTURES=" << rx.numCaptures() << rx.capturedTexts();
	
	if (rx.numCaptures() == 5)
	{
		if (rx.cap(1).length() > 0) *time = rx.cap(1).toDouble();
		if (rx.cap(2).length() > 0) *frame = rx.cap(2).toInt();
		if (rx.cap(3).length() > 0) *percent = rx.cap(3).toInt();
		if (rx.cap(4).length() > 0) *speed = rx.cap(4).toDouble();
		if (rx.cap(5).length() > 0) *remain = rx.cap(5).toInt();
	}

	*warning = warn;
	return true;
}

void InterfaceMEncoder::cliCmdTargetVcd(QString *cmd, QStringList *args,
		const QString &in, const QString &out, const QString &standard)
{
	cmd->clear();
	args->clear();

	if ( settings->input.source.media != Video::Media::DVD )
	{
		qDebug() << "InterfaceMEncoder::cliCmdTargetVcd() supports only DVD input";
		return;
	}

	// Prepare required parameters
	int title = settings->input.video.title;
	int audioId = settings->input.audio.aid;
	QString audioLang = settings->input.audio.language;
	int subtitleId = settings->input.subtitle.sid;
	QString subtitleLang = settings->input.subtitle.language;
		
	// Command
	*cmd = exec.toLatin1();

	*args << "-ovc" << "lavc" << "-oac" << "lavc";
	*args << "-of" << "mpeg" << "-mpegopts" << "format=xvcd";
	*args << "-srate" << "44100" << "-af" << "lavcresample=44100";

	if (standard == "PAL")
	{
		// Append the harddup video filter at the end of the filter chain to avoid A/V sync issue
		*args << "-vf" << "scale=352:288,harddup";
		*args << "-ofps" << "25";
	}
	else
	{
		// Append the harddup video filter at the end of the filter chain to avoid A/V sync issue
		*args << "-vf" << "scale=352:240,harddup";
		*args << "-ofps" << "30000/1001";
	}

	QString aspect = (settings->input.video.display_aspect > 1.5) ? "16/9" : "4/3";
	
	QStringList lavcopts;
	lavcopts << "vcodec=mpeg1video" 
		<< "keyint=15" 
		<< "vrc_buf_size=327" 
		<< "vrc_minrate=1152" 
		<< "vbitrate=1152" 
		<< "vrc_maxrate=1152" 
		<< "acodec=mp2" 
		<< "abitrate=224" 
		<< QString("aspect=%1").arg(aspect);

	*args << "-lavcopts" << lavcopts.join(":");
		
    *args << "-o" << out;
	*args << "-dvd-device" << in << QString("dvd://%1").arg(QString::number(title));
	
	if (audioId > -1)
	{
	  *args << "-aid" << QString::number(audioId);
	}
	else if (!audioLang.isEmpty() && audioLang != "en")
	{
	  *args << "-alang" << QString("%1,en").arg(audioLang);
	}
	else
	{
	  *args << "-alang" << "en";
	}

	if (subtitleId > -1)
	{
	  *args << "-sid" << QString::number(subtitleId);
	}
	else if (!subtitleLang.isEmpty() && subtitleLang != "en")
	{
	  *args << "-slang" << QString("%1,en").arg(subtitleLang);
	}
	else if (!subtitleLang.isEmpty())
	{
	  *args << "-slang" << "en";
	}
	else
	{
		*args << "-nosub";
	}

	qDebug() << "InterfaceMEncoder::cliCmdTargetVcd() returns command:" << *cmd << "with options" << *args;
}

void InterfaceMEncoder::cliCmdTargetSvcd(QString *cmd, QStringList *args,
		const QString &in, const QString &out, const QString &standard)
{
	cmd->clear();
	args->clear();

	if ( settings->input.source.media != Video::Media::DVD )
	{
		qDebug() << "InterfaceMEncoder::cliCmdTargetSvcd() supports only DVD input";
		return;
	}

	// Prepare required parameters
	int title = settings->input.video.title;
	int audioId = settings->input.audio.aid;
	QString audioLang = settings->input.audio.language;
	int subtitleId = settings->input.subtitle.sid;
	QString subtitleLang = settings->input.subtitle.language;
		
	// Command
	*cmd = exec.toLatin1();

	*args << "-ovc" << "lavc" << "-oac" << "lavc";
	*args << "-of" << "mpeg" << "-mpegopts" << "format=xvcd";
	*args << "-srate" << "44100" << "-af" << "lavcresample=44100";

	if (standard == "PAL")
	{
		// Append the harddup video filter at the end of the filter chain to avoid A/V sync issue
		*args << "-vf" << "scale=480:576,harddup";
		*args << "-ofps" << "25";
	}
	else
	{
		// Append the harddup video filter at the end of the filter chain to avoid A/V sync issue
		*args << "-vf" << "scale=480:480,harddup";
		*args << "-ofps" << "30000/1001";
	}

	QString aspect = (settings->input.video.display_aspect > 1.5) ? "16/9" : "4/3";
	
	QStringList lavcopts;
	lavcopts << "vcodec=mpeg2video" 
		<< "keyint=15" 
		<< "mbd=2" 
		<< "vrc_buf_size=917" 
		<< "vrc_minrate=600" 
		<< "vbitrate=2500" 
		<< "vrc_maxrate=2500" 
		<< "acodec=mp2" 
		<< "abitrate=224" 
		<< QString("aspect=%1").arg(aspect);

	*args << "-lavcopts" << lavcopts.join(":");
		
    *args << "-o" << out;
	*args << "-dvd-device" << in << QString("dvd://%1").arg(QString::number(title));
	
	if (audioId > -1)
	{
	  *args << "-aid" << QString::number(audioId);
	}
	else if (!audioLang.isEmpty() && audioLang != "en")
	{
	  *args << "-alang" << QString("%1,en").arg(audioLang);
	}
	else
	{
	  *args << "-alang" << "en";
	}

	if (subtitleId > -1)
	{
	  *args << "-sid" << QString::number(subtitleId);
	}
	else if (!subtitleLang.isEmpty() && subtitleLang != "en")
	{
	  *args << "-slang" << QString("%1,en").arg(subtitleLang);
	}
	else if (!subtitleLang.isEmpty())
	{
	  *args << "-slang" << "en";
	}
	else
	{
		*args << "-nosub";
	}

	qDebug() << "InterfaceMEncoder::cliCmdTargetSvcd() returns command:" << *cmd << "with options" << *args;
}
