/*****************************************************************************
 *
 *  encoder.cpp -- Audio/Video encoder.
 *
 *  This is the encoder thread.
 *
 *  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.
 *
 *****************************************************************************/

#include "../main/paths.h"
#include "../video/video_functions.h"
#include "encoder.h"
#include "macros.h"
#include <QDir>
#include <QProcess>
#include <QRegExp>
#include <QLibrary>
#include <QDebug>

Encoder::Encoder(QTextEdit *stdIn, QTextEdit *stdOut, QTextEdit *stdErr,
	QTextEdit *defLog, const int verbosityLevel) 
	: QObject(),
	ffmpeg(0), ffmpegSettings(0),
	mencoder(0), mencoderSettings(0)
{
	// Set IO channels from parent channels
	standardInput = stdIn;
	standardOutput = stdOut;
	standardError = stdErr;
	verbosity = verbosityLevel;
	log = defLog;

	setVideoNames();
	setAudioNames();
	setSubtitleNames();
	setMuxerNames();

	setMuxerLongNames();

	setVideoShortNames();
	setAudioShortNames();
	setSubtitleShortNames();
	setMuxerShortNames();

	setVideoSynonyms();
	setAudioSynonyms();
	setSubtitleSynonyms();
	setMuxerSynonyms();

	setPreferredVideo();
	setPreferredAudio();
	setPreferredSubtitle();

	input = new encoder_settings_t::input_t;
	outputFile = new encoder_target_t;

	// Now MUST be initialized before using it
}

void Encoder::setMuxerLongNames()
{
	muxerLongNames.clear();

	muxerLongNames[ "264" ] = tr("H.264 - H.264/AVC video stream");
	muxerLongNames[ "3gp" ] = tr("3GP - 3G mobile phone (3GPP/UMTS)");
	muxerLongNames[ "3g2" ] = tr("3G2 - 3G mobile phone (3GPP2/CDMA2000)");
	muxerLongNames[ "ac3" ] = tr("Audio AC3 - Dolby Digital audio stream");
	muxerLongNames[ "adts" ] = tr("Audio AAC - MP4 AAC audio stream");
	muxerLongNames[ "aiff" ] = tr("Audio AIFF - Audio Interchange File Format (Apple)");
	muxerLongNames[ "amr" ] = tr("Audio 3GP - 3G mobile phone audio stream (3GPP/3GPP2)");
	muxerLongNames[ "asf" ] = tr("ASF - Widows Media Streaming Format");
	muxerLongNames[ "au" ] = tr("Audio AU - Sun Unix audio steam");
	muxerLongNames[ "avi" ] = tr("AVI - Microsoft format (DivX/Xvid/MPEG-4)");
	muxerLongNames[ "avm2" ] = tr("SWF - ShockWave Flash 9 Video");
	muxerLongNames[ "dnxhd" ] = tr("MXF - Avid SMPTE VC-3 post production HD video stream");
	muxerLongNames[ "dts" ] = tr("Audio DTS - DTS audio stream");
	muxerLongNames[ "dv" ] = tr("DV Sony - Digital Video tape stream");
	muxerLongNames[ "dvd" ] = tr("MPEG-2 PS/DVD - DVD-Video file");
	muxerLongNames[ "f64be" ] = tr("Audio PCM 64-bit Big-Endian - PCM audio stream");
	muxerLongNames[ "f64le" ] = tr("Audio PCM 64-bit Little-Endian - PCM audio stream");
	muxerLongNames[ "filmstrip" ] = tr("Adobe Filmstrip - Adobe Premiere video steam");
	muxerLongNames[ "flac" ] = tr("Audio FLAC - Lossless audio stream");
	muxerLongNames[ "flv" ] = tr("FLV - Flash Video (Dailymotion/YouTube)");
	muxerLongNames[ "h261" ] = tr("TS - H.261 stream in MPEG-TS file");
	muxerLongNames[ "h263" ] = tr("TS - H.263 stream in MPEG-TS file");
	muxerLongNames[ "h264" ] = tr("TS - H.264 stream in MPEG-TS file");
	muxerLongNames[ "ipod" ] = tr("IPOD - iPod MPEG-4 movie");
	muxerLongNames[ "m4v" ] = tr("M4V - Apple iTunes MPEG-4 movie");
	muxerLongNames[ "matroska" ] = tr("MKV - Matroska (DivX Plus HD/WebM)");
	muxerLongNames[ "mkv" ] = tr("MKV - Matroska video multi-stream format");
	muxerLongNames[ "mov" ] = tr("MOV - Apple QuickTime movie");
	muxerLongNames[ "mp2" ] = tr("Audio MP2 - MPEG layer 2 audio stream");
	muxerLongNames[ "mp3" ] = tr("Audio MP3 - MPEG layer 3 audio stream");
	muxerLongNames[ "m4a" ] = tr("Audio M4A - Apple iTunes MPEG-4 audio");
	muxerLongNames[ "m4v" ] = tr("M4V - Apple iTunes movie");
	muxerLongNames[ "mp4" ] = tr("MP4 - MPEG-4 movie");
	muxerLongNames[ "mpeg" ] = tr("MPEG-2 - MPEG PS (SVCD-DVD)");
	muxerLongNames[ "mpeg_vcd" ] = tr("MPEG-1 - MPEG PS (VideoCD)");
	muxerLongNames[ "mpeg1video" ] = tr("M1V - MPEG-1 Video stream");
	muxerLongNames[ "mpeg2video" ] = tr("M2V - MPEG-2 Video stream");
	muxerLongNames[ "mpegts" ] = tr("TS - MPEG-1/2 Transport Stream");
	muxerLongNames[ "mxf" ] = tr("MXF - Material eXchange Format"); 
	//muxerLongNames[ "null" ] = tr("Raw null video format"); 
	muxerLongNames[ "nut" ] = tr("NUT - Patent-free open format"); 
	muxerLongNames[ "ogg" ] = tr("OGG - Ogg Vorbis patent-free open format");
	muxerLongNames[ "psp" ] = tr("PSP - PlayStation Portable MPEG-4 movie");
	muxerLongNames[ "raw" ] = tr("RAW - Raw video stream");
	muxerLongNames[ "rawaudio" ] = tr("RAWAUDIO - Raw audio stream");
	muxerLongNames[ "rawvideo" ] = tr("RAWVIDEO - Raw video stream");
	muxerLongNames[ "rcv" ] = tr("RCV - VC-1 bitstream (WMV9 Advanced Profile)");
	muxerLongNames[ "rm" ] = tr("RM - Real Media internet video");
	muxerLongNames[ "RoQ" ] = tr("RoQ - Quake Video format");
	muxerLongNames[ "s16be" ] = tr("Audio PCM 16-bit Big-Endian - PCM audio stream");
	muxerLongNames[ "s16le" ] = tr("Audio PCM 16-bit Little-Endian - PCM audio stream");
	muxerLongNames[ "s32be" ] = tr("Audio PCM 32-bit Big-Endian - PCM audio stream");
	muxerLongNames[ "s32le" ] = tr("Audio PCM 32-bit Little-Endian - PCM audio stream");
	muxerLongNames[ "s64be" ] = tr("Audio PCM 64-bit Big-Endian - PCM audio stream");
	muxerLongNames[ "s64le" ] = tr("Audio PCM 64-bit Little-Endian - PCM audio stream");
	muxerLongNames[ "spdif" ] = tr("Audio S/PDIF - Digital audio data link layer protocol");
	muxerLongNames[ "swf" ] = tr("SWF - ShockWave Flash 10 Video");
	muxerLongNames[ "svcd" ] = tr("MPEG-2 PS/SVCD - Super-VideoCD file");
	muxerLongNames[ "vcd" ] = tr("MPEG-1 PS/VCD - VideoCD file");
	muxerLongNames[ "vob" ] = tr("MPEG-2 PS/VOB - DVD VOB file");
	muxerLongNames[ "wav" ] = tr("Audio WAV - Wave audio format (ADPCM/MP3/PCM)");
	muxerLongNames[ "wmv" ] = tr("WMV - Windows Media Video");
}

void Encoder::setMuxerNames()
{
	muxerNames.clear();

	muxerNames[ "264" ] = ".264 - H.264 video";
	muxerNames[ "3gp" ] = "3GP - 3G mobile phone";
	muxerNames[ "3g2" ] = "3G2 - 3G mobile phone";
	muxerNames[ "ac3" ] = "AC3 - Dolby Digital audio";
	muxerNames[ "adts" ] = "ADTS - MPEG-4 AAC audio";
	muxerNames[ "aiff" ] = "AIFF - Apple audio";
	muxerNames[ "amr" ] = "AMR - 3GPP/3GPP2 mobile phone audio";
	muxerNames[ "asf" ] = "ASF - Windows Media";
	muxerNames[ "au" ] = "AU - Sun Unix audio";
	muxerNames[ "avi" ] = "AVI - Audio Video Interleaved";
	muxerNames[ "avm2" ] = "SWF - ShockWave Flash 9";
	muxerNames[ "dnxhd" ] = "MXF - Avid SMPTE VC-3";
	muxerNames[ "dts" ] = "DTS - Audio DTS";
	muxerNames[ "dv" ] = "DV - Digital Video tape stream";
	muxerNames[ "dvd" ] = "MPEG-2 - DVD-Video file";
	muxerNames[ "f64be" ] = ".f64be - PCM 64-bit Big-Endian";
	muxerNames[ "f64le" ] = ".f64le - PCM 64-bit Little-Endian";
	muxerNames[ "filmstrip" ] = "Filmstrip - Adobe Premiere video";
	muxerNames[ "flac" ] = "FLAC - Lossless audio";
	muxerNames[ "flv" ] = "FLV - Flash Video";
	muxerNames[ "h261" ] = "TS - H.261 stream";
	muxerNames[ "h263" ] = "TS - H.263 stream";
	muxerNames[ "h264" ] = "TS - H.264 stream";
	muxerNames[ "ipod" ] = "IPOD - iPod movie";
	muxerNames[ "m4a" ] = "Audio M4A - Apple iTunes audio";
	muxerNames[ "m4v" ] = "M4V - Apple iTunes movie";
	muxerNames[ "matroska" ] = "MKV - Matroska format";
	muxerNames[ "mkv" ] = "MKV - Matroska format";
	muxerNames[ "mov" ] = "MOV - Apple QuickTime movie";
	muxerNames[ "mp2" ] = "MP2 - MPEG layer 2 audio";
	muxerNames[ "mp3" ] = "MP3 - MPEG layer 3 audio";
	muxerNames[ "mp4" ] = "MP4 - MPEG-4 movie";
	muxerNames[ "mpeg" ] = "MPEG-2 - MPEG Program Stream";
	muxerNames[ "mpeg_vcd" ] = "MPEG-1 - MPEG Program Stream";
	muxerNames[ "mpeg1video" ] = "M1V - MPEG-1 Video";
	muxerNames[ "mpeg2video" ] = "M2V - MPEG-2 Video";
	muxerNames[ "mpegts" ] = "TS - MPEG Transport Stream";
	muxerNames[ "mxf" ] = "MXF - Material eXchange Format"; 
	//muxerNames[ "null" ] = "Raw null video format"; 
	muxerNames[ "nut" ] = "NUT - Open format"; 
	muxerNames[ "ogg" ] = "OGG - Ogg Vorbis";
	muxerNames[ "psp" ] = "PSP - PlayStation Portable movie";
	muxerNames[ "raw" ] = "RAW - Raw video";
	muxerNames[ "rawaudio" ] = "RAWAUDIO - Raw audio";
	muxerNames[ "rawvideo" ] = "RAWVIDEO - Raw video";
	muxerNames[ "rcv" ] = "RCV - VC-1 bitstream";
	muxerNames[ "rm" ] = "RM - Real Media";
	muxerNames[ "RoQ" ] = "RoQ - Quake Video";
	muxerNames[ "s16be" ] = ".s16be - PCM 16-bit Big-Endian";
	muxerNames[ "s16le" ] = ".s16le - PCM 16-bit Little-Endian";
	muxerNames[ "s32be" ] = ".s32be - PCM 32-bit Big-Endian";
	muxerNames[ "s32le" ] = ".s32le - PCM 32-bit Little-Endian";
	muxerNames[ "s64be" ] = ".s64be - PCM 64-bit Big-Endian";
	muxerNames[ "s64le" ] = ".s64le - PCM 64-bit Little-Endian";
	muxerNames[ "spdif" ] = "S/PDIF - Digital audio data link";
	muxerNames[ "swf" ] = "SWF - ShockWave Flash";
	muxerNames[ "svcd" ] = "MPEG-2 SVCD - Super-VideoCD";
	muxerNames[ "vcd" ] = "MPEG-1 VCD - VideoCD";
	muxerNames[ "vob" ] = "MPEG-2 VOB - DVD VOB file";
	muxerNames[ "wav" ] = "WAV - Wave audio";
	muxerNames[ "webm" ] = "WebM - HTML5 Video";
	muxerNames[ "wmv" ] = "WMV - Windows Media Video";
}

void Encoder::setMuxerShortNames()
{
	muxerShortNames.clear();

	muxerShortNames[ "264" ] = "Raw";
	muxerShortNames[ "3gp" ] = "3GPP";
	muxerShortNames[ "3g2" ] = "3GPP2";
	muxerShortNames[ "ac3" ] = "Audio AC3";
	muxerShortNames[ "adts" ] = "Audio AAC";
	muxerShortNames[ "aiff" ] = "Audio AIFF";
	muxerShortNames[ "amr" ] = "Audio 3GPP";
	muxerShortNames[ "asf" ] = "ASF";
	muxerShortNames[ "au" ] = "Audio Sun AU";
	muxerShortNames[ "avi" ] = "AVI";
	muxerShortNames[ "avm2" ] = "Flash 9";
	muxerShortNames[ "dnxhd" ] = "SMPTE VC-3";
	muxerShortNames[ "dts" ] = "DTS";
	muxerShortNames[ "dv" ] = "DV";
	muxerShortNames[ "dvd" ] = "MPEG-2 DVD";
	muxerShortNames[ "f64be" ] = "Audio PCM 64be";
	muxerShortNames[ "f64le" ] = "Audio PCM 64le";
	muxerShortNames[ "filmstrip" ] = "Filmstrip";
	muxerShortNames[ "flac" ] = "FLAC";
	muxerShortNames[ "flv" ] = "Flash Video";
	muxerShortNames[ "h261" ] = "H.261";
	muxerShortNames[ "h263" ] = "H.263";
	muxerShortNames[ "h264" ] = "H.264";
	muxerShortNames[ "ipod" ] = "iPod";
	muxerShortNames[ "m4a" ] = "Audio MPEG-4";
	muxerShortNames[ "m4v" ] = "MPEG-4 video";
	muxerShortNames[ "matroska" ] = "MKV";
	muxerShortNames[ "mkv" ] = "MKV";
	muxerShortNames[ "mov" ] = "QuickTime";
	muxerShortNames[ "mp2" ] = "Audio MPEG layer 2";
	muxerShortNames[ "mp3" ] = "MP3";
	muxerShortNames[ "mp4" ] = "MP4";
	muxerShortNames[ "mpeg" ] = "MPEG-1 PS";
	muxerShortNames[ "mpeg1video" ] = "MPEG-1 Video";
	muxerShortNames[ "mpeg2video" ] = "MPEG-2 Video";
	muxerShortNames[ "mpegts" ] = "MPEG Transport";
	muxerShortNames[ "mxf" ] = "MXF"; 
	//muxerShortNames[ "null" ] = "nullt"; 
	muxerShortNames[ "nut" ] = "NUT"; 
	muxerShortNames[ "ogg" ] = "Ogg Vorbis";
	muxerShortNames[ "psp" ] = "MPEG-4 PSP";
	muxerShortNames[ "raw" ] = "Raw";
	muxerShortNames[ "rawaudio" ] = "Audio raw";
	muxerShortNames[ "rawvideo" ] = "Video raw";
	muxerShortNames[ "rcv" ] = "VC-1";
	muxerShortNames[ "rm" ] = "Real Media";
	muxerShortNames[ "RoQ" ] = "RoQ/Quake";
	muxerShortNames[ "s16be" ] = "Audio PCM 16be";
	muxerShortNames[ "s16le" ] = "Audio PCM 16le";
	muxerShortNames[ "s32be" ] = "Audio PCM 32be";
	muxerShortNames[ "s32le" ] = "Audio PCM 32le";
	muxerShortNames[ "s64be" ] = "Audio PCM 64be";
	muxerShortNames[ "s64le" ] = "Audio PCM 64le";
	muxerShortNames[ "spdif" ] = "S/PDIF";
	muxerShortNames[ "swf" ] = "Shockwave Flash";
	muxerShortNames[ "svcd" ] = "MPEG-2 SVCD";
	muxerShortNames[ "vcd" ] = "MPEG-1 VCD";
	muxerShortNames[ "vob" ] = "MPEG-2 VOB";
	muxerShortNames[ "wav" ] = "Audio Waveform";
	muxerShortNames[ "webm" ] = "WebM";
	muxerShortNames[ "wmv" ] = "Windows Media Video";
}

void Encoder::setVideoNames()
{
	videoNames.clear();
	
	videoNames[ "asv1" ] = "ASUS v1";
	videoNames[ "asv2" ] = "ASUS v2";
	videoNames[ "auto" ] = "Chosen by the encoder";
	videoNames[ "bmp" ] = "BMP image";
	videoNames[ "copy" ] = "Stream copy";
	videoNames[ "dnxhd" ] = "VC3/DNxHD";
	videoNames[ "dv" ] = "Sony DV";
	videoNames[ "dvvideo" ] = "Sony DV";
	videoNames[ "flashsv" ] = "Flash Screen Video";
	videoNames[ "flv" ] = "Flash Video";
	videoNames[ "ffv1" ] = "FFmpeg's experimental wavelet-based codec";
	videoNames[ "ffvhuff" ] = "Non-standard 20% smaller HuffYUV using YV1";
	videoNames[ "frameno" ] = "Audio-only/3-pass";
	videoNames[ "gif" ] = "GIF";
	videoNames[ "h261" ] = "H.261";
	videoNames[ "h263" ] = "H.263";
	videoNames[ "huffyuv" ] = "Huffyuv";
	videoNames[ "jpegls" ] = "JPEG LS";
	videoNames[ "theora" ] = "Theora";
	videoNames[ "ljpeg" ] = "Lossless JPEG";
	videoNames[ "mjpeg" ] = "Motion JPEG";
	videoNames[ "mpeg1video" ] = "MPEG-1/VideoCD";
	videoNames[ "mpeg2video" ] = "MPEG-2/DVD-SVCD-CVCD";
	videoNames[ "mpeg4" ] = "MPEG-4";
	videoNames[ "msmpeg4" ] = "MPEG-4 Part 2 - MS v3  - DivX 4/5";  
	videoNames[ "msmpeg4v1" ] = "MPEG-4 Part 2 - MS v1 - DivX 3";
	videoNames[ "msmpeg4v2" ] = "MPEG-4 Part 2 - MS v2";
	videoNames[ "novideo" ] = tr("No video (extract audio)");
	videoNames[ "nuv" ] = "NuppelVideo/RTJPEG";
	videoNames[ "png" ] = "PNG image";
	videoNames[ "qtrle" ] = "QuickTime Animation";
	videoNames[ "raw" ] = "Raw stream";
	videoNames[ "rawvideo" ] = "Raw stream";
	videoNames[ "roqvideo" ] = "RoQ/Quake Video";
	videoNames[ "rv10" ] = "Real 1.0";
	videoNames[ "rv20" ] = "Real 2.0";
	videoNames[ "snow" ] = "FFmpeg wavelet";
	videoNames[ "svq1" ] = "Sorenson video 1";
	videoNames[ "svq3" ] = "Sorenson H.263 used in Flash Video";
	videoNames[ "targa" ] = "Targa image";
	videoNames[ "vp8" ] = "VP8 (WebM video)";
	videoNames[ "wmv1" ] = "Windows Media Video 7";
	videoNames[ "wmv2" ] = "Windows Media Video 8";
	videoNames[ "x264" ] = "H.264/AVC";
	videoNames[ "x264_lr" ] = "H.264/AVC (Mobile)";
	videoNames[ "x264_hd" ] = "H.264/AVC (HDTV)";
	videoNames[ "x264_psp" ] = "H.264/AVC";
	videoNames[ "x264_divx" ] = "DivX Plus HD (H.264/AVC)";
	videoNames[ "xvid" ] = "Xvid (DivX/MPEG-4)";
	videoNames[ "zmbv" ] = "Zip Motion Blocks";
}

void Encoder::setVideoShortNames()
{
	videoShortNames.clear();
	
	videoShortNames[ "asv1" ] = "ASUS v1";
	videoShortNames[ "asv2" ] = "ASUS v2";
	videoShortNames[ "auto" ] = "Chosen by the encoder";
	videoShortNames[ "bmp" ] = "BMP image";
	videoShortNames[ "copy" ] = "Stream copy";
	videoShortNames[ "dnxhd" ] = "VC3/DNxHD";
	videoShortNames[ "dv" ] = "Sony DV";
	videoShortNames[ "dvvideo" ] = "Sony DV";
	videoShortNames[ "flashsv" ] = "Flash Screen Video";
	videoShortNames[ "flv" ] = "Flash Video";
	videoShortNames[ "ffv1" ] = "FFmpeg wavelet";
	videoShortNames[ "ffvhuff" ] = "Huffyuv modified";
	videoShortNames[ "frameno" ] = "Audio-only/3-pass";
	videoShortNames[ "gif" ] = "GIF";
	videoShortNames[ "h261" ] = "H.261";
	videoShortNames[ "h263" ] = "H.263";
	videoShortNames[ "huffyuv" ] = "Huffyuv";
	videoShortNames[ "jpegls" ] = "JPEG LS";
	videoShortNames[ "theora" ] = "Theora";
	videoShortNames[ "ljpeg" ] = "Lossless JPEG";
	videoShortNames[ "mjpeg" ] = "Motion JPEG";
	videoShortNames[ "mpeg1video" ] = "MPEG-1";
	videoShortNames[ "mpeg2video" ] = "MPEG-2";
	videoShortNames[ "mpeg4" ] = "MPEG-4";
	videoShortNames[ "msmpeg4" ] = "MPEG-4 - DivX 4/5";  
	videoShortNames[ "msmpeg4v1" ] = "MPEG-4 DivX 3";
	videoShortNames[ "msmpeg4v2" ] = "MPEG-4 MS v2";
	videoShortNames[ "novideo" ] = tr("No video");
	videoShortNames[ "nuv" ] = "NuppelVideo/RTJPEG";
	videoShortNames[ "png" ] = "PNG image";
	videoShortNames[ "qtrle" ] = "QuickTime Animation";
	videoShortNames[ "raw" ] = "Raw stream";
	videoShortNames[ "rawvideo" ] = "Raw stream";
	videoShortNames[ "roqvideo" ] = "Quake Video";
	videoShortNames[ "rv10" ] = "Real 1.0";
	videoShortNames[ "rv20" ] = "Real 2.0";
	videoShortNames[ "snow" ] = "FFmpeg wavelet";
	videoShortNames[ "svq1" ] = "Sorenson 1";
	videoShortNames[ "svq3" ] = "Sorenson 3";
	videoShortNames[ "targa" ] = "Targa image";
	videoShortNames[ "vp8" ] = "VP8";
	videoShortNames[ "wmv1" ] = "WMV7";
	videoShortNames[ "wmv2" ] = "WMV8";
	videoShortNames[ "x264" ] = "H.264";
	videoShortNames[ "x264_lr" ] = "H.264";
	videoShortNames[ "x264_hd" ] = "H.264";
	videoShortNames[ "x264_psp" ] = "H.264";
	videoShortNames[ "x264_divx" ] = "DivX Plus HD (H.264/AVC)";
	videoShortNames[ "xvid" ] = "Xvid";
	videoShortNames[ "zmbv" ] = "Zip Motion Blocks";
}

void Encoder::setAudioNames()
{
	audioNames.clear();

	audioNames[ "aac" ] = "AAC - MPEG-4";
	audioNames[ "aac_hq" ] = "AAC - MPEG-4 (High Quality)";
	audioNames[ "aac_flv" ] = "AAC - MPEG-4";
	audioNames[ "aac_lr" ] = "AAC - MPEG-4 (Mobile)";  // AAC LowRate is a virtual codec :-)
	audioNames[ "ac3" ] = "AC3";
	audioNames[ "ac3_copy" ] = "AC3 (copy audio)";
	audioNames[ "adpcm_ima_qt" ] = "ADPCM IMA QuickTime";
	audioNames[ "adpcm_ima_wav" ] = "ADPCM IMA WAV";
	audioNames[ "adpcm_ms" ] = "ADPCM Microsoft";
	audioNames[ "adpcm_swf" ] = "ADPCM Shockwave Flash";
	audioNames[ "alac" ] = "Apple Lossless Audio Codec";
	audioNames[ "amrnb" ] = "AMR-NB speech audio (GPP TS 26.073)";
	audioNames[ "auto" ] = "Chosen by the encoder";
	audioNames[ "copy" ] = "Stream copy";
	audioNames[ "faac" ] = "AAC - MPEG-4";
	audioNames[ "flac" ] = "Free Lossless Audio Codec";
	audioNames[ "g726" ] = "G.726 ADPCM";
	audioNames[ "gsm" ] = "GSM 06.10";
	audioNames[ "gsm_ms" ] = "Microsoft GSM";
	audioNames[ "lame" ] = "MP3 - MPEG Audio Layer 3";
	audioNames[ "faac" ] = "AAC - MPEG-4";
	audioNames[ "gsm" ] = "GSM 06.10";
	audioNames[ "amrnb" ] = "AMR-NB speech audio (GPP TS 26.073)";
	audioNames[ "vorbis" ] = "Vorbis";
	audioNames[ "mp2" ] = "MPEG Audio Layer 2";
	audioNames[ "mp2_vcd" ] = "MPEG Audio Layer 2 (VideoCD)";
	audioNames[ "mp3" ] = "MP3 - MPEG Audio Layer 3";
	audioNames[ "mp3_lr" ] = "MP3 - MPEG Audio Layer 3 (Mobile)";
	audioNames[ "mp3_flv" ] = "MP3 - MPEG Audio Layer 3";
	audioNames[ "mp3_flv_lr" ] = "MP3 - MPEG Audio Layer 3 (Mobile)";
	audioNames[ "mp3lame" ] = "MP3 - MPEG Audio Layer 3";
	audioNames[ "multi" ] = tr("Multiple audio streams");
	audioNames[ "noaudio" ] = "No audio"; 
	audioNames[ "none" ] = "No audio"; 
	audioNames[ "pcm_alaw" ] = "PCM A-law";
	audioNames[ "pcm" ] = "PCM - Linear PCM";
	audioNames[ "pcm_f64be" ] = "PCM 64-bit Big-Endian";
	audioNames[ "pcm_f64le" ] = "PCM 64-bit Little-Endian";
	audioNames[ "pcm_s32be" ] = "PCM 32-bit Big-Endian";
	audioNames[ "pcm_s32le" ] = "PCM 32-bit Little-Endian";
	audioNames[ "raw" ] = "Raw stream";
	audioNames[ "roq_dpcm" ] = "RoQ/Quake DPCM";
	audioNames[ "sonic" ] = "Sonic";
	audioNames[ "sonicls" ] = "Sonic Lossless";
	audioNames[ "toolame" ] = "MPEG Audio Layer 2";
	audioNames[ "twolame" ] = "MPEG Audio Layer 2";
	audioNames[ "vorbis" ] = "Vorbis";
	audioNames[ "wmav1" ] = "WMA v1";
	audioNames[ "wmav2" ] = "WMA v2";
}

void Encoder::setAudioShortNames()
{
	audioShortNames.clear();

	audioShortNames[ "aac" ] = "AAC";
	audioShortNames[ "aac_hq" ] = "AAC";
	audioShortNames[ "aac_lr" ] = "AAC";
	audioShortNames[ "aac_flv" ] = "AAC";
	audioShortNames[ "ac3" ] = "AC3";
	audioShortNames[ "ac3_copy" ] = "AC3 (copy)";
	audioShortNames[ "adpcm_ima_qt" ] = "ADPCM";
	audioShortNames[ "adpcm_ima_wav" ] = "ADPCM";
	audioShortNames[ "adpcm_ms" ] = "ADPCM";
	audioShortNames[ "adpcm_swf" ] = "ADPCM";
	audioShortNames[ "alac" ] = "Apple Lossless Audio";
	audioShortNames[ "amrnb" ] = "AMR-NB";
	audioShortNames[ "auto" ] = "Auto";
	audioShortNames[ "copy" ] = "Copy";
	audioShortNames[ "faac" ] = "AAC";
	audioShortNames[ "flac" ] = "Free Lossless Audio";
	audioShortNames[ "g726" ] = "G.726 ADPCM";
	audioShortNames[ "gsm" ] = "GSM 06.10";
	audioShortNames[ "gsm_ms" ] = "Microsoft GSM";
	audioShortNames[ "lame" ] = "MP3";
	audioShortNames[ "faac" ] = "AAC";
	audioShortNames[ "gsm" ] = "GSM 06.10";
	audioShortNames[ "amrnb" ] = "AMR-NB";
	audioShortNames[ "vorbis" ] = "Vorbis";
	audioShortNames[ "mp2" ] = "MPEG-2 Audio";
	audioShortNames[ "mp2_vcd" ] = "MPEG-2 Audio";
	audioShortNames[ "mp3" ] = "MP3";
	audioShortNames[ "mp3_lr" ] = "MP3 (Mobile)";
	audioShortNames[ "mp3_flv" ] = "MP3";
	audioShortNames[ "mp3_flv_lr" ] = "MP3 (Mobile)";
	audioShortNames[ "mp3lame" ] = "MP3";
	audioShortNames[ "multi" ] = tr("Multiple audio");
	audioShortNames[ "noaudio" ] = "No audio"; 
	audioShortNames[ "none" ] = "No audio"; 
	audioShortNames[ "pcm" ] = "PCM Linear";
	audioShortNames[ "pcm_alaw" ] = "PCM A-law";
	audioShortNames[ "pcm_f64be" ] = "PCM 64be";
	audioShortNames[ "pcm_f64le" ] = "PCM 64le";
	audioShortNames[ "pcm_s32be" ] = "PCM 32be";
	audioShortNames[ "pcm_s32le" ] = "PCM 32le";
	audioShortNames[ "raw" ] = "Raw";
	audioShortNames[ "roq_dpcm" ] = "Quake DPCM";
	audioShortNames[ "sonic" ] = "Sonic";
	audioShortNames[ "sonicls" ] = "Sonic Lossless";
	audioShortNames[ "toolame" ] = "MPEG-2 Audio";
	audioShortNames[ "twolame" ] = "MPEG-2 Audio";
	audioShortNames[ "vorbis" ] = "Vorbis";
	audioShortNames[ "wmav1" ] = "Windows Media Audio v1";
	audioShortNames[ "wmav2" ] = "Windows Media Audio v2";
}

void Encoder::setSubtitleNames()
{
	subtitleNames.clear();

	subtitleNames[ "auto" ] = "Chosen by the encoder";
	subtitleNames[ "copy" ] = "Stream copy";
	subtitleNames[ "dvbsub" ] = "DVB subtitles";
	subtitleNames[ "dvdsub" ] = "DVD subtitles";
	subtitleNames[ "inlay" ] = "Inlayed";
	subtitleNames[ "multi" ] = tr("Multiple subtitle streams");
	subtitleNames[ "nosubtitle" ] = tr("No subtitle");
	subtitleNames[ "xsub" ] = "DivX subtitles";
}

void Encoder::setSubtitleShortNames()
{
	subtitleShortNames.clear();

	subtitleShortNames[ "auto" ] = "Auto";
	subtitleShortNames[ "copy" ] = "Stream copy";
	subtitleShortNames[ "dvbsub" ] = "DVB subtitles";
	subtitleShortNames[ "dvdsub" ] = "DVD subtitles";
	subtitleShortNames[ "inlay" ] = "Inlayed";
	subtitleShortNames[ "multi" ] = tr("Multiple subtitle");
	subtitleShortNames[ "nosubtitle" ] = tr("No subtitle");
	subtitleShortNames[ "xsub" ] = "DivX subtitles";
}

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

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

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

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

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

	audioSynonyms[ "aac" ] << "faac" << "libfaac";
	audioSynonyms[ "aac_lr" ] << "faac" << "libfaac";
	audioSynonyms[ "aac_flv" ] << "faac" << "libfaac";
	audioSynonyms[ "amrnb" ] << "libopencore_amrnb";
	audioSynonyms[ "gsm" ] << "libgsm";
	audioSynonyms[ "mp2" ] << "toolame" << "twolame";
	audioSynonyms[ "mp3" ] << "lame" << "libmp3lame" << "mp3lame";
	audioSynonyms[ "mp3_flv" ] << "lame" << "libmp3lame" << "mp3lame";
	audioSynonyms[ "vorbis" ] << "libvorbis";
}

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

void Encoder::setPreferredVideo()
{
	preferredVideo["__default"] = "x264";
	preferredVideo[ "3g2" ] = "mpeg4";
	preferredVideo[ "3gp" ] = "mpeg4";
	preferredVideo[ "ac3" ] = "novideo";
	preferredVideo[ "adts" ] = "novideo";
	preferredVideo[ "asf" ] = "wmv1";
	preferredVideo[ "amr" ] = "novideo";
	preferredVideo[ "au" ] = "novideo";
	preferredVideo[ "avi" ] = "xvid";
	preferredVideo[ "avm2" ] = "mpeg4";
	preferredVideo[ "dnxhd" ] = "dnxhd";
	preferredVideo[ "dts" ] = "novideo";
	preferredVideo[ "dv" ] = "dv";
	preferredVideo[ "dvd" ] = "mpeg2video";
	preferredVideo[ "f64be" ] = "novideo";
	preferredVideo[ "f64le" ] = "novideo";
	preferredVideo[ "filmstrip" ] = "auto";
	preferredVideo[ "flac" ] = "novideo";
	preferredVideo[ "flv" ] = "mpeg4";
	preferredVideo[ "h261" ] = "h261";
	preferredVideo[ "h263" ] = "h263";
	preferredVideo[ "h264" ] = "x264";
	preferredVideo[ "ipod" ] = "x264";
	preferredVideo[ "m4v" ] = "mpeg4";
	preferredVideo[ "matroska" ] = "x264_divx";
	preferredVideo[ "mkv" ] = "x264_divx";
	preferredVideo[ "mov" ] = "mpeg4";
	preferredVideo[ "mp2" ] = "novideo";
	preferredVideo[ "mp3" ] = "novideo";
	preferredVideo[ "mp4" ] = "mpeg4";
	preferredVideo[ "mpeg" ] = "mpeg2video";
	preferredVideo[ "mpeg1video" ] = "mpeg1video";
	preferredVideo[ "mpeg2video" ] = "mpeg2video";
	preferredVideo[ "mpegts" ] = "x264";
	preferredVideo[ "mxf" ] = "dnxhd";
	preferredVideo[ "null" ] = "raw"; 
	preferredVideo[ "nut" ] = "nuv"; 
	preferredVideo[ "ogg" ] = "theora";
	preferredVideo[ "psp" ] = "x264_psp";
	preferredVideo[ "raw" ] = "auto";
	preferredVideo[ "rawaudio" ] = "novideo";
	preferredVideo[ "rawvideo" ] = "copy";
	preferredVideo[ "rcv" ] = "wmv2";
	preferredVideo[ "rm" ] = "rv20";
	preferredVideo[ "RoQ" ] = "roqvideo";
	preferredVideo[ "s32be" ] = "novideo";
	preferredVideo[ "s32le" ] = "novideo";
	preferredVideo[ "spdif" ] = "novideo";
	preferredVideo[ "swf" ] = "mpeg4";
	preferredVideo[ "svcd" ] = "mpeg2video";
	preferredVideo[ "vcd" ] = "mpeg1video";
	preferredVideo[ "vob" ] = "mpeg2video";
	preferredVideo[ "wav" ] = "novideo";
}

void Encoder::setPreferredAudio()
{
	preferredAudio["__default"]["__default"] = "mp3";
	preferredAudio["__default"][ "x264" ] = "aac";
	preferredAudio["__default"][ "x264_lr" ] = "aac_lr";
	preferredAudio["__default"][ "x264_hq" ] = "aac_hq";
	preferredAudio[ "264" ]["__default"] = "aac";
	preferredAudio[ "3g2" ][ "__default" ] = "amrnb";
	preferredAudio[ "3g2" ][ "h263" ] = "amrnb";
	preferredAudio[ "3g2" ][ "mpeg4" ] = "aac_lr";
	preferredAudio[ "3g2" ][ "x264_lr" ] = "aac_lr";
	preferredAudio[ "3g2" ][ "x264" ] = "aac_lr";
	//preferredAudio[ "3g2" ][ "x264_hd" ] = "aac";
	preferredAudio[ "3gp" ][ "__default" ] = "amrnb";
	preferredAudio[ "3g2" ][ "h263" ] = "amrnb";
	preferredAudio[ "3gp" ][ "mpeg4" ] = "aac_lr";
	preferredAudio[ "3gp" ][ "x264_lr" ] = "aac_lr";
	preferredAudio[ "3gp" ][ "x264" ] = "aac_lr";
	//preferredAudio[ "3gp" ][ "x264_hd" ] = "aac";
	preferredAudio[ "ac3" ][ "__default" ] = "ac3";
	preferredAudio[ "adts" ][ "__default" ] = "aac";
	preferredAudio[ "asf" ][ "__default" ] = "wmav1";
	preferredAudio[ "amr" ][ "__default" ] = "amr";
	preferredAudio[ "au" ][ "__default" ] = "pcm_s32be";
	preferredAudio[ "avi" ][ "__default" ] = "mp3";
	preferredAudio[ "avm2" ][ "__default" ] = "aac";
	preferredAudio[ "dnxhd" ][ "__default" ] = "noaudio";
	preferredAudio[ "dts" ][ "__default" ] = "copy";
	preferredAudio[ "dv" ][ "__default" ] = "pcm_s32be";
	preferredAudio[ "dvd" ][ "__default" ] = "mp2";
	preferredAudio[ "f64be" ][ "__default" ] = "pcm_f64be";
	preferredAudio[ "f64le" ][ "__default" ] = "pcm_f64le";
	preferredAudio[ "filmstrip" ][ "__default" ] = "noaudio";
	preferredAudio[ "flac" ][ "__default" ] = "flac";
	preferredAudio[ "flv" ][ "__default" ] = "aac_flv";
	preferredAudio[ "h261" ][ "__default" ] = "mp3";
	preferredAudio[ "h263" ][ "__default" ] = "mp3";
	preferredAudio[ "h264" ][ "__default" ] = "aac";
	preferredAudio[ "ipod" ][ "__default" ] = "mp3";
	preferredAudio[ "ipod" ][ "x264_hd" ] = "aac_hq";
	preferredAudio[ "ipod" ][ "x264_lr" ] = "aac_lr";
	preferredAudio[ "m4v" ][ "__default" ] = "noaudio";
	preferredAudio[ "matroska" ][ "__default" ] = "ac3";
	preferredAudio[ "matroska" ][ "theora" ] = "vorbis";
	preferredAudio[ "matroska" ][ "x264_divx" ] = "ac3";
	preferredAudio[ "matroska" ][ "x264_hd" ] = "ac3";
	preferredAudio[ "matroska" ][ "xvid" ] = "mp3";
	preferredAudio[ "mkv" ][ "__default" ] = "ac3";
	preferredAudio[ "mkv" ][ "theora" ] = "vorbis";
	preferredAudio[ "mkv" ][ "x264_divx" ] = "ac3";
	preferredAudio[ "mkv" ][ "x264_hd" ] = "ac3";
	preferredAudio[ "mkv" ][ "xvid" ] = "mp3";
	preferredAudio[ "mov" ][ "__default" ] = "mp3";
	preferredAudio[ "mov" ][ "x264_hd" ] = "mp3";
	preferredAudio[ "mov" ][ "x264_lr" ] = "mp3";
	preferredAudio[ "mov" ][ "h263" ] = "mp3_lr";
	preferredAudio[ "mp2" ][ "__default" ] = "mp2";
	preferredAudio[ "mp3" ][ "__default" ] = "mp3";
	preferredAudio[ "mp4" ][ "__default" ] = "mp3";
	preferredAudio[ "mp4" ][ "x264_hd" ] = "aac_hq";
	preferredAudio[ "mov" ][ "x264_lr" ] = "aac_lr";
	preferredAudio[ "mpeg" ][ "__default" ] = "mp2";
	preferredAudio[ "mpeg1video" ][ "__default" ] = "noaudio";
	preferredAudio[ "mpeg2video" ][ "__default" ] = "noaudio";
	preferredAudio[ "mpegts" ][ "__default" ] = "aac";
	preferredAudio[ "mxf" ][ "__default" ] = "pcm_s32be";
	preferredAudio[ "null" ][ "__default" ] = "noaudio"; 
	preferredAudio[ "nut" ][ "__default" ] = "pcm_s32be"; 
	preferredAudio[ "ogg" ][ "__default" ] = "vorbis";
	preferredAudio[ "psp" ][ "__default" ] = "aac";
	preferredAudio[ "raw" ][ "__default" ] = "copy";
	preferredAudio[ "rawaudio" ][ "__default" ] = "copy";
	preferredAudio[ "rawvideo" ][ "__default" ] = "noaudio";
	preferredAudio[ "rcv" ][ "__default" ] = "wmav2";
	preferredAudio[ "rm" ][ "__default" ] = "noaudio";
	preferredAudio[ "RoQ" ][ "__default" ] = "roq_dpcm";
	preferredAudio[ "s32be" ][ "__default" ] = "pcm_s32be";
	preferredAudio[ "s32le" ][ "__default" ] = "pcm_s32le";
	preferredAudio[ "spdif" ][ "__default" ] = "auto";
	preferredAudio[ "swf" ][ "__default" ] = "mp3";
	preferredAudio[ "svcd" ][ "__default" ] = "mp2";
	preferredAudio[ "vcd" ][ "__default" ] = "mp2";
	preferredAudio[ "vob" ][ "__default" ] = "mp2";
	preferredAudio[ "wav" ][ "__default" ] = "mp3";
}

void Encoder::setPreferredSubtitle()
{
	preferredSubtitle["__default"]["__default"] = "inlay";
	preferredSubtitle["avi"]["__default"] = "xsub";
	preferredSubtitle["mkv"]["__default"] = "dvdsub";
}

QStringList Encoder::profileCommandLine(const int engine, const encoder_profile_t *profile)
{
	QStringList args;

	QString output = getOutputFilePath();

	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		args = ffmpeg->profileCommandLine(profile, output);
		break;
	case Video::Encoder::MEncoder:
		args = mencoder->profileCommandLine(profile, output);
		break;
	default:
		break;
	}

	return args;
}

QString Encoder::profileDescription(const encoder_profile_t *profile)
{
	QString str;
	
	if ( profile->video.codec.isEmpty() || profile->video.codec == "novideo" )
	{
		if (profile->audio.codec == "ac3_copy")
		{
			QString strChannels;

			if (!input->audio.channels.isEmpty())
				strChannels = input->audio.channels; 
			else if (input->audio.channel_number == 1)
				strChannels = tr("mono");
			else if (input->audio.channel_number == 2)
				strChannels = tr("stereo");
			else if (input->audio.channel_number == 3)
				strChannels = tr("2.1");
			else if (input->audio.channel_number == 6)
				strChannels = tr("5.1");
			else if (input->audio.channel_number == 8)
				strChannels = tr("7.1");
			else if (input->audio.channel_number > 0)
				strChannels = QString::number(input->audio.channel_number) + tr(" ch.");
	
			str =  tr("AC3 %1 audio (copy) %2 kHz %3 kbps")
						.arg( strChannels )
						.arg( double(input->audio.sampling) / 1000 )
						.arg( input->audio.kbps );
		}
		else if (profile->level == Video::Profile::Copy)
		{
			QString strChannels, strCodec(profile->audio.codec.toUpper());

			if (!input->audio.channels.isEmpty())
				strChannels = input->audio.channels; 
			else if (input->audio.channel_number == 1)
				strChannels = tr("mono");
			else if (input->audio.channel_number == 2)
				strChannels = tr("stereo");
			else if (input->audio.channel_number == 3)
				strChannels = tr("2.1");
			else if (input->audio.channel_number == 6)
				strChannels = tr("5.1");
			else if (input->audio.channel_number == 8)
				strChannels = tr("7.1");
			else if (input->audio.channel_number > 0)
				strChannels = QString::number(input->audio.channel_number) + tr(" ch.");
	
			str =  tr("%1 %2 audio %3 kHz %4 kbps")
						.arg( audioShortName(strCodec) )
						.arg( strChannels )
						.arg( double(input->audio.sampling) / 1000 )
						.arg( input->audio.kbps );
		}
		else if (profile->audio.bitrate > 0.0)
		{
			str =  tr("%1 audio %2 kHz %3 kbps")
						.arg( audioShortName(profile->audio.codec) )
						.arg( double(profile->audio.sampling) / 1000 )
						.arg( profile->audio.bitrate );
		}
		else if (profile->audio.codec == "alac" || profile->audio.codec == "flac")
		{
			str =  tr("%1 %2 kHz")
						.arg( audioShortName(profile->audio.codec) )
						.arg( double(profile->audio.sampling) / 1000 );
		}
		else
		{
			str =  tr("%1 audio %2 kHz VBR")
						.arg( audioShortName(profile->audio.codec) )
						.arg( double(profile->audio.sampling) / 1000 );
		}
	}
	else if ( profile->audio.codec.isEmpty() || profile->audio.codec == "noaudio" )
	{
		str =  tr("%1 video %2x%3 %4 kbps")
						.arg( videoShortName(profile->video.codec) )
						.arg( profile->video.rez.width() ).arg( profile->video.rez.height() )
						.arg( profile->video.bitrate );
	}
	else
	{
		if (profile->audio.sampling == -1 || profile->audio.codec == "ac3_copy")
		{
			QString strChannels;

			if (!input->audio.channels.isEmpty())
				strChannels = input->audio.channels; 
			else if (input->audio.channel_number == 1)
				strChannels = tr("mono");
			else if (input->audio.channel_number == 2)
				strChannels = tr("stereo");
			else if (input->audio.channel_number == 3)
				strChannels = tr("2.1");
			else if (input->audio.channel_number == 6)
				strChannels = tr("5.1");
			else if (input->audio.channel_number == 8)
				strChannels = tr("7.1");
			else if (input->audio.channel_number > 0)
				strChannels = QString::number(input->audio.channel_number) + tr(" ch.");
	
			str =  tr("%1 video %2x%3 %4 kbps,  AC3 %5 audio (copy) %6 kHz %7 kbps")
						.arg( videoShortName(profile->video.codec) )
						.arg( profile->video.rez.width() ).arg( profile->video.rez.height() )
						.arg( profile->video.bitrate )
						.arg( strChannels )
						.arg( double(input->audio.sampling) / 1000 )
						.arg( input->audio.kbps );
		}
		else if (profile->audio.bitrate > 0.0)
		{
			str =  tr("%1 video %2x%3 %4 kbps,  %5 audio %6 kHz %7 kbps")
						.arg( videoShortName(profile->video.codec) )
						.arg( profile->video.rez.width() ).arg( profile->video.rez.height() )
						.arg( profile->video.bitrate )
						.arg( audioShortName(profile->audio.codec) )
						.arg( double(profile->audio.sampling) / 1000 )
						.arg( profile->audio.bitrate );
		}
		else if (profile->audio.codec == "alac" || profile->audio.codec == "flac")
		{
			str =  tr("%1 video %2x%3 %4 kbps,  %5 %6 kHz")
						.arg( videoShortName(profile->video.codec) )
						.arg( profile->video.rez.width() ).arg( profile->video.rez.height() )
						.arg( profile->video.bitrate )
						.arg( audioShortName(profile->audio.codec) )
						.arg( double(profile->audio.sampling) / 1000 );
		}
		else
		{
			str =  tr("%1 video %2x%3 %4 kbps,  %5 audio %6 kHz VBR")
						.arg( videoShortName(profile->video.codec) )
						.arg( profile->video.rez.width() ).arg( profile->video.rez.height() )
						.arg( profile->video.bitrate )
						.arg( audioShortName(profile->audio.codec) )
						.arg( double(profile->audio.sampling) / 1000 );
		}
	}

	return str;
}

bool Encoder::activateInterface(const int engine, const QString &path)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		ffmpegSettings = new encoder_settings_t;
		ffmpegStatus = new encoder_engine_status_t;
		ffmpegCapability = new encoder_engine_capability_t;
		ffmpegCapability->video = &ffmpegVideos; 
		ffmpegCapability->audio = &ffmpegAudios;
		ffmpegCapability->subtitle = &ffmpegSubtitles;
		ffmpegCapability->muxer = &ffmpegMuxers;
		ffmpegCapability->libVideo = 0; 
		ffmpegCapability->libAudio = 0; 
		ffmpegCapability->libSubtitle = 0; 
		ffmpegCapability->libMuxer = 0; 
		ffmpeg = new InterfaceFFmpeg();
		ffmpeg->initialize(path, ffmpegCapability, ffmpegSettings, ffmpegStatus);
		setLatency(engine, DefaultLatencyStart, DefaultLatencyFinished, DefaultLatencyKill);
		reset(engine);
		return isInterfaceReady(engine);
		break;
	case Video::Encoder::MEncoder:
		mencoderSettings = new encoder_settings_t;
		mencoderStatus = new encoder_engine_status_t;
		mencoderCapability = new encoder_engine_capability_t;
		mencoderCapability->video = &mencoderVideos; 
		mencoderCapability->audio = &mencoderAudios;
		mencoderCapability->subtitle = &mencoderSubtitles;
		mencoderCapability->muxer = &mencoderMuxers;
		mencoderCapability->libVideo = &mencoderLibVideos; 
		mencoderCapability->libAudio = &mencoderLibAudios; 
		mencoderCapability->libSubtitle = &mencoderLibSubtitles; 
		mencoderCapability->libMuxer = &mencoderLibMuxers; 
		mencoder = new InterfaceMEncoder();
		mencoder->initialize(path, mencoderCapability, mencoderSettings, mencoderStatus);
		setLatency(engine, DefaultLatencyStart, DefaultLatencyFinished, DefaultLatencyKill);
		reset(engine);
		return isInterfaceReady(engine);
		break;
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return false;
	}
}

int Encoder::latencyStart(const int engine)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpegLatency.start;
	case Video::Encoder::MEncoder:
		return mencoderLatency.start;
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return DefaultLatencyStart;
	}
}

int Encoder::latencyFinished(const int engine)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpegLatency.finished;
	case Video::Encoder::MEncoder:
		return mencoderLatency.finished;
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return DefaultLatencyFinished;
	}
}

int Encoder::latencyKill(const int engine)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpegLatency.kill;
	case Video::Encoder::MEncoder:
		return mencoderLatency.kill;
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return DefaultLatencyKill;
	}
}

void Encoder::setLatency(const int engine, const int start, const int finished, const int kill)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		ffmpegLatency.start = start;
		ffmpegLatency.finished = finished;
		ffmpegLatency.kill = kill;
		return;
	case Video::Encoder::MEncoder:
		mencoderLatency.start = start;
		mencoderLatency.finished = finished;
		mencoderLatency.kill = kill;
		return;
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return;
	}
}

void Encoder::setBinPath(const int engine,  const QString &path)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		ffmpeg->setBinPath(path);
		break;
	case Video::Encoder::MEncoder:
		mencoder->setBinPath(path);
		break;
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return;
	}

	reset(engine);
}

void Encoder::setInputPath(const QString &path, const int media)
{
	input->source.path = path;
	input->source.media = media;
}

void Encoder::updateInputTracks(video_t v, bool nv,	audio_t a, bool na, subtitle_t s, bool ns)
{
	// We'll do and updateAdditionalInputTracks() for multi-audio/sub
	
	input->video = v;
	input->no_video = nv;
	
	input->audio = a;
	input->no_audio = na;

	input->subtitle = s;
	input->no_subtitle = ns;
}

bool Encoder::isReady()
{
	return ffmpeg->isReady() && mencoder->isReady();
}

bool Encoder::isInterfaceReady(const int engine)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpeg->isReady();
	case Video::Encoder::MEncoder:
		return mencoder->isReady();
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return false;
	}
}

bool Encoder::isSupportedMuxer(const int engine, const QString &muxer)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpeg->muxerSupport(muxer);
	case Video::Encoder::MEncoder:
		return mencoder->muxerSupport(muxer);
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return false;
	}
}

bool Encoder::isSupportedVideo(const int engine, const QString &muxer, const QString &video)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpeg->muxerSupportVideo(muxer, video);
	case Video::Encoder::MEncoder:
		return mencoder->muxerSupportVideo(muxer, video);
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return false;
	}
}

bool Encoder::isSupportedAudio(const int engine, const QString &muxer, const QString &audio)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpeg->muxerSupportAudio(muxer, audio);
	case Video::Encoder::MEncoder:
		return mencoder->muxerSupportAudio(muxer, audio);
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return false;
	}
}

bool Encoder::isSupportedSubtitle(const int engine, const QString &muxer, const QString &subtitle)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpeg->muxerSupportSubtitle(muxer, subtitle);
	case Video::Encoder::MEncoder:
		return mencoder->muxerSupportSubtitle(muxer, subtitle);
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return false;
	}
}

void Encoder::initialize(/*Latency latency*/)
{
	// Read application settings
	readSettings();
}

void Encoder::readInterfaceLatency(const int engine, int *start, int *finished, int *kill)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		*start = ffmpegLatency.start;
		*finished = ffmpegLatency.finished;
		*kill = ffmpegLatency.kill;
		break;
	case Video::Encoder::MEncoder:
		*start = mencoderLatency.start;
		*finished = mencoderLatency.finished;
		*kill = mencoderLatency.kill;
		break;
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		*start = DefaultLatencyStart;
		*finished = DefaultLatencyFinished;
		*kill = DefaultLatencyKill;
		break;
	}
}

void Encoder::reset(const int engine)
{
	// Run test process to get signature and capabilities
	qDebug() << "Encoder: begin reset engine type" << engine;
	printLog(tr("Encoder: %1 engine reset begins.").arg(name(engine)), VERBOSITY_VERBOSE);

	QString binPath;
	encoder_engine_capability_t *capability;;
	encoder_engine_status_t *status;

	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		binPath = ffmpeg->getBinPath();
		status = ffmpegStatus;
		capability = ffmpegCapability;
		break;
	case Video::Encoder::MEncoder:
		binPath = mencoder->getBinPath();
		status = mencoderStatus;
		capability = mencoderCapability;
		break;
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return;
	}

	// Reset encoder status
	status->clear();
	capability->muxer->clear();
	capability->audio->clear();
	capability->video->clear();
	capability->subtitle->clear();

	// 3 tests to run
	bool okVersion, okCodecs, okMuxers;

	// We don't use the encoder process member for this, we use a local QProcess
	QProcess process; // on the stack so no need to delete

	// Get encoder command line
	QString cmd;
	QStringList args;

	int LatencyStart, LatencyFinished, LatencyKill;
	readInterfaceLatency(engine, &LatencyStart, &LatencyFinished, &LatencyKill);

	if ( engine == Video::Encoder::FFmpeg )
	{
		// Get and parse signature
		ffmpeg->cliCmdGetVersion(&cmd, &args);

		// Run!
		QString strIn(cmd);
		strIn.append(" ").append(args.join(" "));
		printIn(strIn);

		qDebug() << "Encoder: start process" << cmd << args;
		printLog(tr("Encoder: %1 process starts.").arg(name(engine)), VERBOSITY_VERBOSE);

#ifdef Q_OS_MAC

#elif defined(Q_OS_LINUX)
		// Linux version got its own FFmpeg build
		if (cmd.contains("ffmpeg", Qt::CaseInsensitive))
		{
			// ffmpeg libs are in binary/../lib
			QDir dir( cmd );
			dir.cdUp();
			dir.cdUp();
			dir.cd( "lib" );
			QString ffmpegLibPath = dir.absolutePath();
			QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
			env.insert("LD_LIBRARY_PATH", ffmpegLibPath);
			process.setProcessEnvironment(env);
		}
#endif

		process.start(cmd, args);
		
		if (!process.waitForStarted(LatencyStart))
		{
			qDebug() << "Encoder: process failed to start, waitForStarted() has timed out at (msec):"
				<< LatencyStart;
			printLog(tr("Encoder: %1 process failed to start in %2 milliseconds.")
				.arg(name(engine)).arg(LatencyStart), VERBOSITY_QUIET);
		
			process.close();  // sounds safe to do this
			return;
		}

		qDebug("Encoder: process started.");
		printLog(tr("Encoder: %1 process started.").arg(name(engine)), VERBOSITY_VERBOSE);

		// Stop command not needed, process ends by itself but takes a few time (LatencyFinished)
		if (!process.waitForFinished(LatencyFinished))
		{
			qDebug("Encoder: process didn't end by itself.");

			process.kill();

			qDebug("Encoder: kill process.");
			printLog(tr("Encoder: %1 process being killed.").arg(name(engine)), VERBOSITY_VERBOSE);

			if (!process.waitForFinished(LatencyKill))
			{
				qDebug("Warning: encoder process still running.");
				printLog(tr("Warning: %1 process still running.").arg(name(engine)), VERBOSITY_VERBOSE);
			}
			else
			{
				qDebug("Encoder: process killed.");
				printLog(tr("Encoder: %1 process killed.").arg(name(engine)), VERBOSITY_VERBOSE);
			}
		}
			
		// Ensure process ended normally
		if ( process.exitStatus() == QProcess::CrashExit )
		{
			qDebug("Warning: encoder process crashed.");
			printLog(tr("Warning: %1 process crashed.").arg(name(engine)), VERBOSITY_NORMAL);
		}
		else
		{
			qDebug() << "Encoder: process finished.";
			printLog(tr("Encoder: %1 process finished.").arg(name(engine)), VERBOSITY_VERBOSE);
		}

		// Read output!
		status->cout = process.readAllStandardOutput();
		status->cerr = process.readAllStandardError();
		process.close();

		// Append outputs to standard IO
		printOut( status->cout );
		printErr( status->cerr );

		// Parse raw data to extract signature for a start
		status->state = Video::Status::RawStatus;

		ffmpeg->parseVersion();

		okVersion = !(status->state == Video::Status::ParseFail);

		// Get and parse codecs
		ffmpeg->cliCmdGetCodecs(&cmd, &args);

		// Run!
		strIn = cmd;
		strIn.append(" ").append(args.join(" "));
		printIn(strIn);

		qDebug() << "Encoder: start process" << cmd << args;
		printLog(tr("Encoder: %1 process starts.").arg(name(engine)), VERBOSITY_VERBOSE);

		process.start(cmd, args);
		
		if (!process.waitForStarted(LatencyStart))
		{
			qDebug() << "Encoder: process failed to start, waitForStarted() has timed out at (msec):"
				<< LatencyStart;
			printLog(tr("Encoder: %1 process failed to start in %2 milliseconds.")
				.arg(name(engine)).arg(LatencyStart), VERBOSITY_QUIET);
		
			process.close();  // sounds safe to do this
			return;
		}

		qDebug("Encoder: process started.");
		printLog(tr("Encoder: %1 process started.").arg(name(engine)), VERBOSITY_VERBOSE);

		// Stop command not needed, process ends by itself but takes a few time (LatencyFinished)
		if (!process.waitForFinished(LatencyFinished))
		{
			qDebug("Encoder: process didn't end by itself.");

			process.kill();

			qDebug("Encoder: kill process.");
			printLog(tr("Encoder: %1 process being killed.").arg(name(engine)), VERBOSITY_VERBOSE);

			if (!process.waitForFinished(LatencyKill))
			{
				qDebug("Warning: encoder process still running.");
				printLog(tr("Warning: %1 process still running.").arg(name(engine)), VERBOSITY_VERBOSE);
			}
			else
			{
					qDebug("Encoder: process killed.");
				printLog(tr("Encoder: %1 process killed.").arg(name(engine)), VERBOSITY_VERBOSE);
			}
		}
			
		// Ensure process ended normally
		if ( process.exitStatus() == QProcess::CrashExit )
		{
			qDebug("Warning: encoder process crashed.");
			printLog(tr("Warning: %1 process crashed.").arg(name(engine)), VERBOSITY_NORMAL);
		}
		else
		{
			qDebug() << "Encoder: process finished.";
			printLog(tr("Encoder: %1 process finished.").arg(name(engine)), VERBOSITY_VERBOSE);
		}

		// Read output!
		status->cout = process.readAllStandardOutput();
		status->cerr = process.readAllStandardError();
		process.close();

		// Append outputs to standard IO
		printOut( status->cout );
		printErr( status->cerr );

		// Parse raw data to extract codecs capabilities, and we're almost
		status->state = Video::Status::RawStatus;

		ffmpeg->parseCodecs();

		okCodecs = !(status->state == Video::Status::ParseFail);

		// Get and parse muxers
		ffmpeg->cliCmdGetMuxers(&cmd, &args);

		// Run!
		strIn = cmd;
		strIn.append(" ").append(args.join(" "));
		printIn(strIn);

		qDebug() << "Encoder: start process" << cmd << args;
		printLog(tr("Encoder: %1 process starts.").arg(name(engine)), VERBOSITY_VERBOSE);

		process.start(cmd, args);
		
		if (!process.waitForStarted(LatencyStart))
		{
			qDebug() << "Encoder: process failed to start, waitForStarted() has timed out at (msec):"
				<< LatencyStart;
			printLog(tr("Encoder: %1 process failed to start in %2 milliseconds.")
				.arg(name(engine)).arg(LatencyStart), VERBOSITY_NORMAL);
		
			process.close();  // sounds safe to do this
			return;
		}

		qDebug("Encoder: process started.");
		printLog(tr("Encoder: %1 process started.").arg(name(engine)), VERBOSITY_VERBOSE);

		// Stop command not needed, process ends by itself but takes a few time (LatencyFinished)
		if (!process.waitForFinished(LatencyFinished))
		{
			qDebug("Encoder: process didn't end by itself.");

			process.kill();

			qDebug("Encoder: kill process.");
			printLog(tr("Encoder: %1 process being killed.").arg(name(engine)), VERBOSITY_VERBOSE);

			if (!process.waitForFinished(LatencyKill))
			{
				qDebug("Warning: encoder process still running.");
				printLog(tr("Warning: %1 process still running.").arg(name(engine)), VERBOSITY_VERBOSE);
			}
			else
			{
					qDebug("Encoder: process killed.");
				printLog(tr("Encoder: %1 process killed.").arg(name(engine)), VERBOSITY_VERBOSE);
			}
		}
			
		// Ensure process ended normally
		if ( process.exitStatus() == QProcess::CrashExit )
		{
			qDebug("Warning: encoder process crashed.");
			printLog(tr("Warning: %1 process crashed.").arg(name(engine)), VERBOSITY_NORMAL);
		}
		else
		{
			qDebug() << "Encoder: process finished.";
			printLog(tr("Encoder: %1 process finished.").arg(name(engine)), VERBOSITY_VERBOSE);
		}

		// Read output!
		status->cout = process.readAllStandardOutput();
		status->cerr = process.readAllStandardError();
		process.close();

		// Append outputs to standard IO
		printOut( status->cout );
		printErr( status->cerr );

		// Parse raw data to extract muxer capabilities, and we're done!
		status->state = Video::Status::RawStatus;

		ffmpeg->parseMuxers();

		printLog(tr("Encoder: %1 engine reset completed.").arg(name(engine)), VERBOSITY_VERBOSE);

		okMuxers = !(status->state == Video::Status::ParseFail);

		if ( okVersion && okCodecs && okMuxers )
		{
			status->state = Video::Status::EngineOk;

			printLog(tr("Encoder: %1 engine is ready.").arg(name(engine)), VERBOSITY_VERBOSE);
		}
		else
		{
			status->state = Video::Status::ParseFail;

			printLog(tr("Encoder: %1 engine binary is %2").arg(name(engine)).arg(binPath), VERBOSITY_QUIET);
			printLog(tr("Encoder: %1 engine failed initialization.").arg(name(engine)), VERBOSITY_QUIET);
		}
	}
	else
	{
		if ( engine == Video::Encoder::MEncoder )
		{
			mencoder->cliCmdGetStatus(&cmd, &args);
		}
		else
		{
			status->state = Video::Status::Unknown;

			printLog(tr("Encoder: %1 engine binary is %2").arg(name(engine)).arg(binPath), VERBOSITY_QUIET);
			printLog(tr("Encoder: %1 engine failed initialization.").arg(name(engine)), VERBOSITY_QUIET);
			return;
		}		

		// Run!
		QString strIn(cmd);
		strIn.append(" ").append(args.join(" "));
		printIn(strIn);

		qDebug() << "Encoder: start process" << cmd << args;
		printLog(tr("Encoder: %1 process starts.").arg(name(engine)), VERBOSITY_VERBOSE);

		process.start(cmd, args);
		
		if (!process.waitForStarted(LatencyStart))
		{
			qDebug() << "Encoder: process failed to start, waitForStarted() has timed out at (msec):"
				<< LatencyStart;
			printLog(tr("Encoder: %1 process failed to start in %2 milliseconds.")
				.arg(name(engine)).arg(LatencyStart), VERBOSITY_NORMAL);
		
			process.close();  // sounds safe to do this
			return;
		}

		qDebug("Encoder: process started.");
		printLog(tr("Encoder: %1 process started.").arg(name(engine)), VERBOSITY_VERBOSE);

		// Stop command not needed, process ends by itself but takes a few time (LatencyFinished)
		if (!process.waitForFinished(LatencyFinished))
		{
			qDebug("Encoder: process didn't end by itself.");

			process.kill();

			qDebug("Encoder: kill process.");
			printLog(tr("Encoder: %1 process being killed.").arg(name(engine)), VERBOSITY_VERBOSE);

			if (!process.waitForFinished(LatencyKill))
			{
				qDebug("Warning: encoder process still running.");
				printLog(tr("Warning: %1 process still running.").arg(name(engine)), VERBOSITY_VERBOSE);
			}
			else
			{
					qDebug("Encoder: process killed.");
				printLog(tr("Encoder: %1 process killed.").arg(name(engine)), VERBOSITY_VERBOSE);
			}
		}
			
		// Ensure process ended normally
		if ( process.exitStatus() == QProcess::CrashExit )
		{
			qDebug("Warning: encoder process crashed.");
			printLog(tr("Warning: %1 process crashed.").arg(name(engine)), VERBOSITY_NORMAL);
		}
		else
		{
			qDebug() << "Encoder: process finished.";
			printLog(tr("Encoder: %1 process finished.").arg(name(engine)), VERBOSITY_VERBOSE);
		}

		// Read output!
		status->cout = process.readAllStandardOutput();
		status->cerr = process.readAllStandardError();
		process.close();

		// Append outputs to standard IO
		printOut( status->cout );
		printErr( status->cerr );

		status->state = Video::Status::RawStatus;

		// Parse raw data to extract status and capabilities, and we're done!
		if ( engine == Video::Encoder::MEncoder )
		{
			mencoder->parseStatus();
		}
		else
		{
			status->state = Video::Status::Unknown;

			printLog(tr("Encoder: %1 engine binary is %2").arg(name(engine)).arg(binPath), VERBOSITY_QUIET);
			printLog(tr("Encoder: %1 engine failed initialization.").arg(name(engine)), VERBOSITY_QUIET);
			return;
		}

		printLog(tr("Encoder: %1 engine reset completed.").arg(name(engine)), VERBOSITY_VERBOSE);

		if ( status->state == Video::Status::EngineOk )
		{
			printLog(tr("Encoder: %1 engine is ready.").arg(name(engine)), VERBOSITY_VERBOSE);
		}
		else
		{
			printLog(tr("Encoder: %1 engine binary is %2").arg(name(engine)).arg(binPath), VERBOSITY_QUIET);
			printLog(tr("Encoder: %1 engine failed initialization.").arg(name(engine)), VERBOSITY_QUIET);
		}
	
	}

	qDebug("Encoder: engine reset completed.");
}

encoder_settings_t *Encoder::getSettings(const int engine)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpegSettings;
	case Video::Encoder::MEncoder:
		return mencoderSettings;
	default:
		return 0;
	}
}

encoder_engine_capability_t *Encoder::getCapability(const int engine)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpegCapability;
	case Video::Encoder::MEncoder:
		return mencoderCapability;
	default:
		return 0;
	}
}

encoder_engine_status_t *Encoder::getStatus(const int engine)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpegStatus;
	case Video::Encoder::MEncoder:
		return mencoderStatus;
	default:
		return 0;
	}
}

QString Encoder::getBinPath(const int engine)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpeg->getBinPath();
	case Video::Encoder::MEncoder:
		return mencoder->getBinPath();
	default:
		return 0;
	}
}

QString Encoder::getOutputFilePath()
{
	return QString("%1/%2%3").arg(QDir::cleanPath(outputFile->dir))
							.arg(outputFile->name).arg(outputFile->ext);  
}

QString Encoder::getStatsFilePath()
{
	return QString("%1/%2.stats").arg(QDir::cleanPath(outputFile->dir))
							.arg(outputFile->name);  
}

QString Encoder::getOutputStandard()
{
	// We don't change standard so is input
	QString standard(input->video.standard);

	// Need to guess
	if ( input->video.standard.isEmpty() )
	{
		double fps(input->video.fps);
		double delta(0.005);  // < 0.006 to differentiate 23.976 from 24
	
		if ( (fps > 25.0 - delta && fps < 25.0 + delta)
			|| (fps > 50.0 - delta && fps < 50.0 + delta) )
		{
			standard = "PAL";
		}
		else if ( (fps > 23.976 - delta && fps < 23.976 + delta)
			|| (fps > 24.0 - delta && fps < 24.0 + delta)
			|| (fps > 29.97 - delta && fps < 29.97 + delta)
			|| (fps > 30.0 - delta && fps < 30.0 + delta)
			|| (fps > 60.0 - delta && fps < 60.0 + delta) )
		{
			standard = "NTSC";
		}
	}

	return standard;
}

bool Encoder::audioAndVideoSelected()
{
	return !input->no_video && !input->no_audio;
}

int Encoder::getAudioInputCount()
{
	int n(0);

	if ( mainAudio != - 1 )
	{
		n = 1 + input->additionalAudio.count();
	}

	return n;
}

int Encoder::getSubtitleInputCount()
{
	int n(0);

	if ( mainSubtitle != - 1 )
	{
		n = 1 + input->additionalSubtitle.count();
	}

	return n;
}

QString Encoder::name(const int engine)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return QString("FFmpeg");
	case Video::Encoder::MEncoder:
		return QString("MEncoder");
	default:
		return QString("unknown");
	}
}

QString Encoder::videoName(const QString &codec)
{
	QString name;

	if ( videoNames.contains(codec) )
	{
		name = videoNames[codec];
	}
	else
	{
		name = videoShortName(codec);
	}

	return name;
}

QString Encoder::audioName(const QString &codec)
{
	QString name;

	if ( audioNames.contains(codec) )
	{
		name = audioNames[codec];
	}
	else
	{
		name = audioShortName(codec);
	}

	return name;
}

QString Encoder::subtitleName(const QString &codec)
{
	QString name;

	if ( subtitleNames.contains(codec) )
	{
		name = subtitleNames[codec];
	}
	else
	{
		name = subtitleShortName(codec);
	}

	return name;
}

QString Encoder::muxerName(const QString &muxer)
{
	QString name;

	if ( muxerNames.contains(muxer) )
	{
		name =  muxerNames[muxer];
	}
	else
	{
		name =  muxerShortName(muxer);
	}

	return name;
}

QString Encoder::videoShortName(const QString &codec)
{
	QString name;

	if ( videoNames.contains(codec) )
	{
		name = videoShortNames[codec];
	}
	else
	{
		name = codec.toUpper();  // no nice short name, return the codec name
	}

	return name;
}

QString Encoder::audioShortName(const QString &codec)
{
	QString name;

	if ( audioNames.contains(codec) )
	{
		name = audioShortNames[codec];
	}
	else
	{
		name = codec.toUpper();  // no nice short name, return the codec name
	}

	return name;
}

QString Encoder::subtitleShortName(const QString &codec)
{
	QString name;

	if ( subtitleNames.contains(codec) )
	{
		name = subtitleShortNames[codec];
	}
	else
	{
		name = codec.toUpper();  // no nice short name, return the codec name
	}

	return name;
}

QString Encoder::muxerShortName(const QString &muxer)
{
	QString name;

	if ( muxerNames.contains(muxer) )
	{
		name =  muxerShortNames[muxer];
	}
	else
	{
		name =  muxer.toUpper();  // no nice short name, return the codec name
	}

	return name;
}

QString Encoder::muxerLongName(const QString &muxer)
{
	QString name;

	if ( muxerLongNames.contains(muxer) )
	{
		name =  muxerLongNames[muxer];
	}
	else if ( muxerNames.contains(muxer) )
	{
		name =  muxerNames[muxer];
	}
	else
	{
		name =  muxerShortName(muxer);
	}

	return name;
}

QStringList Encoder::getMuxerSynonyms(const QString &muxer)
{
	QStringList synonyms(muxer);

	if ( muxerSynonyms.contains(muxer) )
	{
		synonyms.append( muxerSynonyms[muxer] );
	}
	else
	{
		
		QMapIterator<QString, QStringList> i(muxerSynonyms);
		while (i.hasNext())
		{
			i.next();
			if ( i.value().contains(muxer) )
			{
				synonyms = i.value();
				synonyms.append( i.key() );
				break;
			}
		}
	}

	return synonyms;		
}

QStringList Encoder::getVideoSynonyms(const QString &codec)
{
	QStringList synonyms(codec);

	if ( videoSynonyms.contains(codec) )
	{
		synonyms.append( videoSynonyms[codec] );
	}
	else
	{
		QMapIterator<QString, QStringList> i(videoSynonyms);
		while (i.hasNext())
		{
			i.next();
			if ( i.value().contains(codec) )
			{
				synonyms = i.value();
				synonyms.append( i.key() );
				break;
			}
		}
	}

	return synonyms;		
}

QStringList Encoder::getAudioSynonyms(const QString &codec)
{
	QStringList synonyms(codec);

	if ( audioSynonyms.contains(codec) )
	{
		//synonyms.append( audioSynonyms[codec] );
	}
	else
	{
		
		QMapIterator<QString, QStringList> i(audioSynonyms);
		while (i.hasNext())
		{
			i.next();
			if ( i.value().contains(codec) )
			{
				synonyms = i.value();
				synonyms.append( i.key() );
				break;
			}
		}
	}

	return synonyms;		
}

QStringList Encoder::getSubtitleSynonyms(const QString &codec)
{
	QStringList synonyms(codec);

	if ( subtitleSynonyms.contains(codec) )
	{
		synonyms.append( subtitleSynonyms[codec] );
	}
	else
	{
		
		QMapIterator<QString, QStringList> i(subtitleSynonyms);
		while (i.hasNext())
		{
			i.next();
			if ( i.value().contains(codec) )
			{
				synonyms = i.value();
				synonyms.append( i.key() );
				break;
			}
		}
	}

	return synonyms;		
}

QStringList Encoder::supportedMuxers()
{
	// The list is given by MEncoder which is required for DVD input 
	// and which supports libavcodecs (so FFmpeg)
	QStringList muxers = mencoder->getSupportedMuxers();

	// Remove video format for no_video input
	if ( input->no_video && input->source.media )
	{
		QSet<QString> audioMuxers;
		QSet<QString> allSuppMuxers = muxers.toSet();

		audioMuxers << "ac3" << "au" << "m4a" << "mp3" << "wav";

		allSuppMuxers.intersect( audioMuxers );

		muxers = allSuppMuxers.toList();
	}

	// Remove formats not supported by MEncoder
	if ( input->source.media == Video::Media::DVD )
	{
		// Theora not supported
		muxers.removeAll("ogg");
		// WebM, VP8 not supported
		muxers.removeAll("webm");
	}

	// Remove formats not supported by FFmpeg
	if ( input->source.media == Video::Media::File )
	{
		// VP8 not supported (unless you're lucky to have a patch for VP8 
		//muxers.removeAll("webm");
	}

	return muxers;
}

bool Encoder::muxerSupport(const int engine, const QString &muxer)
{
	bool supports;

	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		supports = ffmpeg->muxerSupport(muxer);
		break;
	case Video::Encoder::MEncoder:
		supports = mencoder->muxerSupport(muxer);
		break;
	default:
		supports = false;
	}

	return supports;
}

bool Encoder::muxerSupportVideo(const QString &muxer, const QString &video)
{
	bool supported(false);

	int engine= selectConvenientEngine();

	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		supported |= ffmpeg->muxerSupportVideo(muxer, video);
		break;
	case Video::Encoder::MEncoder:
		supported |= ffmpeg->muxerSupportVideo(muxer, video);
		break;
	}

	supported &= isInterfaceReady(engine);

	return supported;
}

bool Encoder::muxerSupportAudio(const QString &muxer, const QString &audio)
{
	if ( input->source.media == Video::Media::DVD
		&& muxer == "mov" && (audio == "ac3" || audio == "ac3_copy") )
	{
		return false;
	}
	
	bool supported(false);

	if ( isInterfaceReady(Video::Encoder::FFmpeg) )
	{
		supported |= ffmpeg->muxerSupportAudio(muxer, audio);
	}

	if ( isInterfaceReady(Video::Encoder::MEncoder) )
	{
		supported |= mencoder->muxerSupportAudio(muxer, audio);
	}

	return supported;
}

bool Encoder::muxerSupportSubtitle(const QString &muxer, const QString &subtitle)
{
	bool supported(false);

	if ( isInterfaceReady(Video::Encoder::FFmpeg) )
	{
		supported |= ffmpeg->muxerSupportSubtitle(muxer, subtitle);
	}

	if ( isInterfaceReady(Video::Encoder::MEncoder) )
	{
		supported |= mencoder->muxerSupportSubtitle(muxer, subtitle);
	}

	return supported;
}

bool Encoder::supportMultiAudio(const int engine)
{
	bool supports;

	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		supports = ffmpeg->supportMultiAudio();
		break;
	case Video::Encoder::MEncoder:
		supports = mencoder->supportMultiAudio();
		break;
	default:
		supports = false;
	}

	return supports;
}

bool Encoder::supportMultiSubtitle(const int engine)
{
	bool supports;

	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		supports = ffmpeg->supportMultiSubtitle();
		break;
	case Video::Encoder::MEncoder:
		supports = mencoder->supportMultiSubtitle();
		break;
	default:
		supports = false;
	}

	return supports;
}

int Encoder::getEstimatedOutputFileSize(const int engine, const int frames)
{
	int fileSize(0);

	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		fileSize = ffmpeg->getEstimatedOutputFileSize(frames);
		break;
	case Video::Encoder::MEncoder:
		break;
	default:
		break;
	}

	return fileSize;
}

bool Encoder::isCmdEncodeValid(const int engine, QString *cmdToCheck, QStringList *argsToCheck, QString *output, 
		QString *stdIn, QString *stdOut, QString *stdErr, int limit)
{
	// Run test process to get signature and capabilities
	qDebug() << "Encoder: begin check command" << cmdToCheck << argsToCheck;
	printLog(tr("Encoder: %1 engine is checking a command.").arg(name(engine)), VERBOSITY_VERBOSE);

	// We don't use the encoder process member for this, we use a local QProcess
	QProcess process; // on the stack so no need to delete

	// Get encoder command line
	QString cmd( *cmdToCheck );
	QStringList args( *argsToCheck );
	QStringList limitArgs;

	if ( engine == Video::Encoder::FFmpeg )
	{
		if ( limit > 0 ) limitArgs << "-fs" << QString::number(limit);

#ifdef Q_OS_MAC

#elif defined(Q_OS_LINUX)
		// Linux version got its own FFmpeg build
		if (cmd.contains("ffmpeg", Qt::CaseInsensitive))
		{
			// ffmpeg libs are in binary/../lib
			QDir dir( cmd );
			dir.cdUp();
			dir.cdUp();
			dir.cd( "lib" );
			QString ffmpegLibPath = dir.absolutePath();
			QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
			env.insert("LD_LIBRARY_PATH", ffmpegLibPath);
			process.setProcessEnvironment(env);
		}
#endif
	}
	else if ( engine == Video::Encoder::MEncoder )
	{
		if ( limit > 0 ) limitArgs << "-frames" << QString::number(limit);
	}
	else
	{
		return true;
	}

	while ( !limitArgs.isEmpty() ) args.prepend( limitArgs.takeLast() );  

	// Run!
	QString strInput(cmd);
	strInput.append(" ").append(args.join(" "));

	qDebug() << "Encoder: start process" << cmd << args;
	printLog(tr("Encoder: %1 process starts.").arg(name(engine)), VERBOSITY_VERBOSE);

	process.start(cmd, args);
	
	if (!process.waitForStarted(latencyStart(engine)))
	{
		qDebug() << "Encoder: process failed to start, waitForStarted() has timed out at (msec):"
			<< latencyStart(engine);
		printLog(tr("Encoder: %1 process failed to start in %2 milliseconds.")
			.arg(name(engine)).arg(latencyStart(engine)), VERBOSITY_NORMAL);
		
		process.close();  // sounds safe to do this
		return false;
	}

	qDebug("Encoder: process started.");
	printLog(tr("Encoder: %1 process started.").arg(name(engine)), VERBOSITY_VERBOSE);

	// Stop command not needed, process ends by itself but takes a few time (LatencyFinished)
	int LatencyFinished = latencyFinished(engine);

	if (!process.waitForFinished(LatencyFinished))
	{
		qDebug("Encoder: process didn't end by itself.");

		process.kill();

		qDebug("Encoder: kill process.");
		printLog(tr("Encoder: %1 process being killed.").arg(name(engine)), VERBOSITY_VERBOSE);

		if (!process.waitForFinished(latencyKill(engine)))
		{
			qDebug("Warning: encoder process still running.");
			printLog(tr("Warning: %1 process still running.").arg(name(engine)), VERBOSITY_VERBOSE);
		}
		else
		{
			qDebug("Encoder: process killed.");
			printLog(tr("Encoder: %1 process killed.").arg(name(engine)), VERBOSITY_VERBOSE);
		}
	}
		
	// Ensure process ended normally
	if ( process.exitStatus() == QProcess::CrashExit )
	{
		qDebug("Warning: encoder process crashed.");
		printLog(tr("Warning: %1 process crashed.").arg(name(engine)), VERBOSITY_NORMAL);
	}

	// Read output!
	QByteArray cout = process.readAllStandardOutput();
	QByteArray cerr = process.readAllStandardError();
	process.close();

	// Return IO to caller
	*stdIn = strInput;
	*stdOut = cout;
	*stdErr = cerr;

	// Delete output file
	QFile file(*output);
	if (file.exists()) file.remove();

	// Parse raw data to extract status and capabilities, and we're done!
	bool res = parseCommandCheck( engine, &cout, &cerr );

	if ( res )
	{
		printLog(tr("Encoder: %1 engine check command completed.").arg(name(engine)), VERBOSITY_VERBOSE);
		
		qDebug("Encoder: check command completed.");
	}
	else
	{
		printLog(tr("Encoder: %1 engine checking command: NOT valid").arg(name(engine)), VERBOSITY_VERBOSE);
		
		qDebug("Encoder: check command completed.");
	}

	return res;
}

QString Encoder::getPreferredVideo(const QString &muxer)
{
	QString video("");

	if ( preferredVideo.contains( muxer ) )
	{
			video = preferredVideo[muxer];
	}
	else if ( preferredVideo.contains( "__default" ) )
	{
			video = preferredVideo["__default"];
	}

	return video;
}

QString Encoder::getPreferredAudio(const QString &muxer, const QString &video)
{
	QString audio("");

	if ( preferredAudio.contains( muxer ) && preferredAudio[muxer].contains( video ) )
	{
			audio = preferredAudio[muxer][video];
	}
	else if ( preferredAudio.contains( "__default" )  && preferredAudio["__default"].contains( video ) )
	{
			audio = preferredAudio["__default"][video];
	}
	else if ( preferredAudio.contains( muxer ) && preferredAudio[muxer].contains( "__default" ) )
	{
			audio = preferredAudio[muxer]["__default"];
	}
	else if ( preferredAudio.contains( "__default" )  && preferredAudio.contains( "__default" ) )
	{
			audio = preferredAudio["__default"]["__default"];
	}

	return audio;
}

QString Encoder::getPreferredSubtitle(const QString &muxer, const QString &video)
{
	QString subtitle("");

	if ( preferredSubtitle.contains( muxer ) && preferredSubtitle[muxer].contains( video ) )
	{
			subtitle = preferredSubtitle[muxer][video];
	}
	else if ( preferredSubtitle.contains( "__default" )  && preferredSubtitle["__default"].contains( video ) )
	{
			subtitle = preferredSubtitle["__default"][video];
	}
	else if ( preferredSubtitle.contains( muxer ) && preferredSubtitle[muxer].contains( "__default" ) )
	{
			subtitle = preferredSubtitle[muxer]["__default"];
	}
	else if ( preferredSubtitle.contains( "__default" )  && preferredSubtitle.contains( "__default" ) )
	{
			subtitle = preferredSubtitle["__default"]["__default"];
	}

	return subtitle;
}

void Encoder::recommendedMuxerCodecs( const QString &muxer, QString *video, QString *audio, QString *subtitle )
{
	 *video = getPreferredVideo(muxer);

	recommendedMuxerVideoCodecs(muxer, *video, audio, subtitle);
}

void Encoder::recommendedMuxerVideoCodecs( const QString &muxer, const QString &video, QString *audio, QString *subtitle )
{
	 *audio = getPreferredAudio(muxer, video);
	 *subtitle = getPreferredSubtitle(muxer, video);
}

void Encoder::setVerbosity(const int verbose)
{
	verbosity = verbose;
}

void Encoder::setSaveSettingsOnClose(const bool save)
{
	saveSettingsOnClose = save;
}

void Encoder::printLog(const QString &message, const int verbosityLevel)
{
	if ( log == 0 )
		qDebug() << "Encoder Log:" << message;
	else if ( verbosityLevel <= verbosity )
		log->append( message );
}

void Encoder::printIn(const QString &message, const int verbosityLevel)
{
	if ( standardInput == 0)
		qDebug() << "Encoder stdIn:" << message;
	else if ( verbosityLevel <= verbosity )
		standardInput->append( message );
}

void Encoder::printOut(const QString &message, const int verbosityLevel)
{
	if ( standardOutput == 0)
		qDebug() << "Encoder stdOut:" << message;
	else if ( verbosityLevel <= verbosity )
		standardOutput->append( message );
}

void Encoder::printErr(const QString &message, const int verbosityLevel)
{
	if ( standardError == 0)
		qDebug() << "Encoder stdErr:" << message;
	else if ( verbosityLevel <= verbosity )
		standardError->append( message );
}


void Encoder::clearLog()
{
	if ( log != 0)
		log->clear();
}

void Encoder::clearIn()
{
	if ( standardInput != 0)
		standardInput->clear();
}

void Encoder::clearOut()
{
	if ( standardOutput != 0)
		standardOutput->clear();
}

void Encoder::clearErr()
{
	if ( standardError != 0)
		standardError->clear();
}

void Encoder::cliChooseCmdEncode(int *engine, QString *cmd, QStringList *args, 
	const QString &output, int frames, int chapter, int seek, bool forceEngine)
{
	// Choose a convenient interface for the current settings
	if (!forceEngine) *engine = selectConvenientEngine();
	
	switch (*engine)
	{
	case Video::Encoder::FFmpeg:
		ffmpegSettings->input = *input;
		//ffmpegSettings->output.options["-metadata"] = QString("Comment=%1").arg(ENCODER_SIGNATURE);
		ffmpeg->setPass(1, 1);
		ffmpeg->cliCmdEncode(cmd, args, output, frames, seek);
		break;
	case Video::Encoder::MEncoder:
		mencoderSettings->input = *input;
		mencoder->setPass(1, 1);
		mencoder->cliCmdEncode(cmd, args, output, frames, chapter, seek);
		break;
	default:
		printErr(tr("encoder interface (type %1) doesn't support encoding").arg(*engine));
	}
}

void Encoder::cliCorrectAspectRatio(const int engine, QString *cmd, QStringList *args,
	const QString &input, const QString &output, double aspect_ratio)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		ffmpeg->cliCorrectAspectRatio(cmd, args, input, output, aspect_ratio);
		break;
	default:
		printErr(tr("encoder interface (type %1) doesn't support aspect ratio correction").arg(engine));
	}
}

void Encoder::cliExtractAudioFromAvi(const int engine, QString *cmd, QStringList *args,
	const QString &input, const QString &output)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		ffmpeg->cliExtractAudioFromAvi(cmd, args, input, output);
		break;
	default:
		printErr(tr("encoder interface (type %1) doesn't support MP3 from AVI extraction").arg(engine));
	}
}

bool Encoder::cliCmdSplitFile(int *engine, QString *cmd, QStringList *args, QString *error,
		const QString &inputFileName, const qint64 inputFileSize, 
		const int partNumber, const qint64 partSize)
{
	*engine = Video::Encoder::FFmpeg;

	if (!ffmpeg->cliCmdSplitFile(cmd, args, inputFileName, inputFileSize, partNumber, partSize))
	{
		*error = tr("error from FFmpeg interface");
		return false;
	}

	return true;
}

void Encoder::cliCmdTargetVcd(const int engine, QString *cmd, QStringList *args,
						const QString &in, const QString &out, const QString &standard)
{
	// Ensure TV standard
	QString	standardTv = standard;
	if ( standardTv.isEmpty() ) standardTv = input->video.standard;
	if ( standardTv.isEmpty() )
	{
		standardTv = input->video.fps == 25.0 || input->video.fps == 50.0 ? "PAL" : "NTSC";
	}
		
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		// File only
		ffmpeg->setPass(1, 1);
		ffmpeg->cliCmdTargetVcd(cmd, args, in, out, standardTv);
		break;
	case Video::Encoder::MEncoder:
		// DVD only
		mencoder->setPass(1, 1);
		mencoder->loadInputSettings(input);
		mencoder->cliCmdTargetVcd(cmd, args, in, out, standardTv);
		break;
	default:
		printErr(tr("encoder interface (type %1) doesn't support VCD target").arg(engine));
	}
}

void Encoder::cliCmdTargetSvcd(const int engine, QString *cmd, QStringList *args,
						const QString &in, const QString &out, const QString &standard)
{
	// Ensure TV standard
	QString	standardTv = standard;
	if ( standardTv.isEmpty() ) standardTv = input->video.standard;
	if ( standardTv.isEmpty() )
	{
		standardTv = input->video.fps == 25.0 || input->video.fps == 50.0 ? "PAL" : "NTSC";
	}
		
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		// File only
		ffmpeg->setPass(1, 1);
		ffmpeg->cliCmdTargetSvcd(cmd, args, in, out, standardTv);
		break;
	case Video::Encoder::MEncoder:
		// DVD only
		mencoder->setPass(1, 1);
		mencoder->loadInputSettings(input);
		mencoder->cliCmdTargetSvcd(cmd, args, in, out, standardTv);
		break;
	default:
		printErr(tr("encoder interface (type %1) doesn't support SVCD target").arg(engine));
	}
}

void Encoder::cliCmdTargetXvid(const int engine, QString *cmd, QStringList *args,
	encoder_settings_t::input_t *inputSettings)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		printErr(tr("FFmpeg encoder interface doesn't support Xvid target"));
		break;
	case Video::Encoder::MEncoder:
		// Set intput settings for Xvid
		mencoderSettings->input = *inputSettings;
		// Reset output settings
		mencoderSettings->output.video.clear();
		mencoderSettings->output.audio.clear();
		mencoderSettings->output.subtitle.clear();
		// AVI Muxer
		mencoderSettings->output.muxer = "avi";
		// Xvid CBR
		if ( qAbs(mencoderSettings->input.video.display_aspect - 1.33) < 0.1 )
		{
			mencoderSettings->output.video.rez = QSize( 512, 384 );
		}
		else
		{
			mencoderSettings->output.video.rez = QSize( 624, 352 );
		}
		mencoderSettings->output.video.codec = "xvid";
		mencoderSettings->output.video.bitrate = 700;
		// MP3 ABR
		mencoderSettings->output.audio.codec = "mp3";
		mencoderSettings->output.audio.sampling = 44100;
		mencoderSettings->output.audio.kbps = 128;
		// Get encoding command
		mencoder->setPass(1, 1);
		mencoder->cliCmdEncode(cmd, args, getOutputFilePath());
		break;
	default:
		printErr(tr("encoder interface (type %1) doesn't support Xvid target").arg(engine));
	}
}

bool Encoder::parseCommandCheck(const int engine, QByteArray *cout, QByteArray *cerr)
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return ffmpeg->parseCommandCheck(cout, cerr);
	case Video::Encoder::MEncoder:
		return mencoder->parseCommandCheck(cout, cerr);
	default:
		printErr(tr("encoder interface (type %1) unknown").arg(engine));
		return false;
	}
}

bool Encoder::parseEngineProgress( int engine, QString *output, QString *warning, 
	int *frame, double *time, int *percent, int *remain, double *speed, int *size )
{
	switch (engine)
	{
	case Video::Encoder::FFmpeg:
		return InterfaceFFmpeg::parseOutput(output, warning, frame, time, percent, remain, speed, size);
		break;
	case Video::Encoder::MEncoder:
		return InterfaceMEncoder::parseOutput(output, warning, frame, time, percent, remain, speed, size);
		break;
	default:
		return false;
	}
}

void Encoder::setOutputMuxer(const QString &muxer)
{	
	outputFile->muxer = muxer;
	outputFile->ext = recommendsFileExtension(outputFile->muxer, input->no_video);
}

QString Encoder::setOutputFile(const QString &folder, const QString &name)
{	
	QString ext = recommendsFileExtension(outputFile->muxer, input->no_video);
	
	outputFile->dir = folder;
	outputFile->name = name;
	outputFile->ext = ext;

	return ext;
}

void Encoder::setOutputLength(const int frames)
{
	ffmpegSettings->output.frames = frames;
	mencoderSettings->output.frames = frames;
}

void Encoder::setOutputVideoCodec(const QString &codec)
{
	ffmpegSettings->output.video.codec = codec;
	mencoderSettings->output.video.codec = codec;
}

void Encoder::setOutputAudioCodec(const QString &codec)
{
	ffmpegSettings->output.audio.codec = codec;
	mencoderSettings->output.audio.codec = codec;
}

void Encoder::setOutputSubtitleCodec(const QString &codec)
{
	ffmpegSettings->output.subtitle.codec = codec;
	mencoderSettings->output.subtitle.codec = codec;
}

void Encoder::setOutputAudioVolume(const int gain)
{
	if (ffmpegSettings) ffmpegSettings->output.audio.volume = gain;
	if (mencoderSettings) mencoderSettings->output.audio.volume = gain;
}

QSize Encoder::recommendsSize(const encoder_video_settings_t *settings, const video_t *source)
{
#pragma message (ToBeDone "complete the size recommendations for MPEG1-2/H.264 - " __FUNCTION__)

	bool assumingPAL = (source->fps == 25.0) || (source->fps == 50.0);
	bool assumingWide = (source->display_aspect > 1.70);

	QSize rez;
	// By default keep aspec ratio
	if (qAbs(1.78 - source->display_aspect) < 0.1)
	{
		rez = QSize(640, 360); // keep 16/9, most generic size
	}
	else if (qAbs(1.33 - source->display_aspect) < 0.1) 
	{
		
		rez = QSize(512, 384); // keep 4/3, most generic size
	}
	else
	{
		// square rez keeping number of lines
		rez = QSize( int( (double)source->rez.height() * source->display_aspect ), source->rez.height());
	}
/*
	// Apply codec and profile on rez recommendation
	if ( settings->codec == "xvid" )
	{
		switch( settings->xvid.profile )
		{
		case DivxHandheld:
			rez = QSize(176, 144);
			break;
		case DivxPortableNtsc:
		case DivxPortablePal:
			rez = QSize(640, 480);
			break;
		case DivxHomeTheatreNtsc:
			rez = QSize(720, 480);
			break;
		case DivxHomeTheatrePal:
			rez = QSize(720, 576);
			break;
		case DivxHighDef:	// HDTV
			rez = QSize(1280, 720);
			break;
		case Simple0:
		case Simple1:
			rez = QSize(176, 144);
			break;
		case Simple2:
		case Simple3:
			rez = QSize(352, assumingPAL ? 288 : 240);
			break;
		case AdvancedSimple0:
		case AdvancedSimple1:
		case AdvancedSimple2:
			rez = QSize(176, 144);
			break;
		case AdvancedSimple3:
			rez = QSize(352, assumingPAL ? 288 : 240);
			break;
		case AdvancedSimple4:
			rez = QSize(352, assumingPAL ? 576 : 480);
			break;
		case AdvancedSimple5:
			rez = QSize(720, assumingPAL ? 576 : 480);
			break;
		case SmallSmartphones:
			rez = QSize(320, 240);
			break;
		case LargeSmartphones:
			rez = QSize(assumingWide ? 400 : 512, assumingWide ? 225 : 384);
			break;
		case Apple_iPhone:
		case Apple_iPad:
		case Apple_MacBook13:
		case Apple_MacBook15:
			rez = QSize(assumingWide ? 640 : 512, assumingWide ? 360 : 384);
			break;
		case Apple_MacBook17:
		case Apple_iMac:
			rez = QSize(assumingWide ? 960 : 720, assumingWide ? 540 : 540);
			break;
		case Archos7:
		case Archos10:
			rez = QSize(assumingWide ? 640 : 512, assumingWide ? 360 : 384);
			break;
		case BlackBerry:
			rez = QSize(assumingWide ? 400 : 512, assumingWide ? 225 : 384);
			break;
		case Netbook10:
		case Netbook12:
		case Laptop13:
		case Laptop15:
			rez = QSize(assumingWide ? 640 : 512, assumingWide ? 360 : 384);
			break;
		case Laptop17:
		case Desktop:
			rez = QSize(assumingWide ? 960 : 720, assumingWide ? 540 : 540);
			break;
		case Free:
		default:
			rez = QSize(assumingWide ? 640 : 512, assumingWide ? 360 : 384);
		}
	}
*/
	return rez;
}

double Encoder::recommendsFps(const encoder_video_settings_t *settings, const video_t *source)
{
#ifdef WIN32
#pragma message (ToBeDone "complete the frame rate recommendations - " __FUNCTION__)
#endif

	double fps(source->fps); // default is source fps

/*	// Apply codec and profile on fps recommendation
	switch( settings->codec )
	{
	case Video::Codec::lavc_libxvid:
	case Video::Codec::xvid:
		////////////////////////////////
		switch( settings->xvid.profile )
		{
		case DivxHandheld:
			rez = QSize(176, 144);
			break;
		case DivxPortableNtsc:
		case DivxPortablePal:
			rez = QSize(640, 480);
			break;
		case DivxHomeTheatreNtsc:
			rez = QSize(720, 480);
			break;
		case DivxHomeTheatrePal:
			rez = QSize(720, 576);
			break;
		case DivxHighDef:	// HDTV
			rez = QSize(1280, 720);
			break;
		case Simple0:
		case Simple1:
			rez = QSize(176, 144);
			break;
		case Simple2:
		case Simple3:
			rez = QSize(352, assumingPAL ? 288 : 240);
			break;
		case AdvancedSimple0:
		case AdvancedSimple1:
		case AdvancedSimple2:
			rez = QSize(176, 144);
			break;
		case AdvancedSimple3:
			rez = QSize(352, assumingPAL ? 288 : 240);
			break;
		case AdvancedSimple4:
			rez = QSize(352, assumingPAL ? 576 : 480);
			break;
		case AdvancedSimple5:
			rez = QSize(720, assumingPAL ? 576 : 480);
			break;
		case SmallSmartphones:
			rez = QSize(320, 240);
			break;
		case LargeSmartphones:
			rez = QSize(assumingWide ? 400 : 512, assumingWide ? 225 : 384);
			break;
		case Apple_iPhone:
		case Apple_iPad:
		case Apple_MacBook13:
		case Apple_MacBook15:
			rez = QSize(assumingWide ? 640 : 512, assumingWide ? 360 : 384);
			break;
		case Apple_MacBook17:
		case Apple_iMac:
			rez = QSize(assumingWide ? 960 : 720, assumingWide ? 540 : 540);
			break;
		case Archos7:
		case Archos10:
			rez = QSize(assumingWide ? 640 : 512, assumingWide ? 360 : 384);
			break;
		case BlackBerry:
			rez = QSize(assumingWide ? 400 : 512, assumingWide ? 225 : 384);
			break;
		case Netbook10:
		case Netbook12:
		case Laptop13:
		case Laptop15:
			rez = QSize(assumingWide ? 640 : 512, assumingWide ? 360 : 384);
			break;
		case Laptop17:
		case Desktop:
			rez = QSize(assumingWide ? 960 : 720, assumingWide ? 540 : 540);
			break;
		case Free:
		default:
			rez = QSize(assumingWide ? 640 : 512, assumingWide ? 360 : 384);
		}
		////////////////////////////////
		break;
	default:
		break;
	}
*/
	return fps;  
}

QString Encoder::recommendsFileExtension( const QString &muxer, const bool novideo )
{
	QString ext;

	if (muxer == "asf")
	{
		ext = ".wmv";
	}
	else if (muxer == "avm2")
	{
		ext = ".swf";
	}
	else if (muxer == "dv")
	{
		ext = ".avi";
	}
	else if (muxer == "filmstrip")
	{
		ext = ".flm";
	}
	else if (muxer == "ipod")
	{
		ext = novideo ? ".m4a" : ".m4v";
	}
	else if (muxer == "matroska")
	{
		ext = ".mkv";
	}
	else if (muxer == "mpeg1video")
	{
		ext = ".m1v";
	}
	else if (muxer == "mpeg2video")
	{
		ext = ".m2v";
	}
	else if (muxer == "mpeg" || muxer == "mpeg_vcd")
	{
		ext = ".mpg";
	}
	else if (muxer == "mpegts")
	{
		ext = ".ts";
	}
	else if (muxer == "mp2")
	{
		ext = ".mpa";
	}
	else if (muxer == "null" || muxer == "raw" || muxer == "rawvideo" || muxer == "rawaudio")
	{
		ext = ".raw";
	}
	else if (muxer == "f64be" || muxer == "f64le" || muxer == "s32be" || muxer == "s32le")
	{
		ext = ".wav";
	}
	else
	{
		ext = "." + muxer.toLower();
	}

	return ext;
}

void Encoder::readSettings()
{
	QSettings userSettings(appOrganization, appApplication);

	userSettings.beginGroup("Encoder");
	
	outputFile->ext = userSettings.value("target ext", ".avi").toString();	
	outputFile->muxer = userSettings.value("target muxer", "avi").toString();	
	//outputFile->split.size = userSettings.value("custom split size", 737).toInt(); 
	//outputFile->split.volumes = userSettings.value("custom split volumes", 1).toInt(); 
	
	userSettings.beginGroup("Engine Preferences");

/*experimental
	// Mencoder
	if (userSettings.contains("MEncoder/deinterlacer"))
	{
		preferences.mencoder->deinterlacer = userSettings.value("Mencoder/deinterlacer").toString();
	}
*/
	userSettings.endGroup();  // Engines

	// Encoder Settings
	userSettings.beginGroup("Encoder Settings");
/*experimental

	if ( engine == Video::Encoder::MEncoder )
	{	
		// MEncoder Settings
		userSettings.beginGroup("MEncoder");

		userSettings.beginGroup("Video Settings");

		settings->output.video.codec = userSettings.value("codec").toString();

		// Video filters
		if ( userSettings.contains("filter/harddup") )
		{
			userSettings.beginGroup("filter");

			settings->output.video.filter.harddup = userSettings.value("harddup").toBool();
			settings->output.video.filter.noskip = userSettings.value("noskip").toBool();

			userSettings.endGroup();  // filter
		}
		else
		{
			settings->output.video.filter.harddup = true;
			settings->output.video.filter.noskip = true;
		}

		// MPEG-1 settings 
		if ( userSettings.contains("mpeg1/resX") )
		{
			userSettings.beginGroup("mpeg1");

			settings->output.video.mpeg1.resX = userSettings.value("resX").toInt();
			settings->output.video.mpeg1.resY = userSettings.value("resY").toInt();
			settings->output.video.mpeg1.mpeg_fps = userSettings.value("mpeg_fps").toInt();
			settings->output.video.mpeg1.bitrate = userSettings.value("bitrate").toInt();
			settings->output.video.mpeg1.stream = userSettings.value("stream").toInt();
			settings->output.video.mpeg1.pack_size = userSettings.value("pack_size").toInt();
			settings->output.video.mpeg1.muxrate = userSettings.value("muxrate").toInt();
			settings->output.video.mpeg1.interleaving2 = userSettings.value("interleaving2").toBool();
			settings->output.video.mpeg1.vdelay = userSettings.value("vdelay").toInt();
			settings->output.video.mpeg1.adelay = userSettings.value("adelay").toInt();
			settings->output.video.mpeg1.drop = userSettings.value("drop").toBool();
			settings->output.video.mpeg1.vbuf_size = userSettings.value("vbuf_size").toInt();
			settings->output.video.mpeg1.abuf_size = userSettings.value("abuf_size").toInt();
			settings->output.video.mpeg1.cbr = userSettings.value("cbr").toBool();
			settings->output.video.mpeg1.minvbr = userSettings.value("minvbr").toInt();
			settings->output.video.mpeg1.maxvbr = userSettings.value("maxvbr").toInt();
			settings->output.video.mpeg1.gop_size = userSettings.value("gop_size").toInt();
			settings->output.video.mpeg1.closed_gop = userSettings.value("closed_gop").toBool();
			settings->output.video.mpeg1.letter_box = userSettings.value("letter_box").toBool();
			settings->output.video.mpeg1.force_vcd = userSettings.value("force_vcd").toBool();

			settings->output.video.user_defined.mpeg1.resX = userSettings.value("user defined width").toInt();
			settings->output.video.user_defined.mpeg1.resY = userSettings.value("user defined height").toInt();

			userSettings.endGroup();  // mpeg1
		}

		// MPEG-2 settings 
		if ( userSettings.contains("mpeg2/resX") )
		{
			userSettings.beginGroup("mpeg2");

			settings->output.video.mpeg2.resX = userSettings.value("resX").toInt();
			settings->output.video.mpeg2.resY = userSettings.value("resY").toInt();
			settings->output.video.mpeg2.mpeg_aspect = userSettings.value("mpeg_aspect").toInt();
			settings->output.video.mpeg2.mpeg_fps = userSettings.value("mpeg_fps").toInt();
			settings->output.video.mpeg2.bitrate = userSettings.value("bitrate").toInt();
			settings->output.video.mpeg2.stream = userSettings.value("stream").toInt();
			settings->output.video.mpeg2.pack_size = userSettings.value("pack_size").toInt();
			settings->output.video.mpeg2.muxrate = userSettings.value("muxrate").toInt();
			settings->output.video.mpeg2.tsaf = userSettings.value("tsaf").toBool();
			settings->output.video.mpeg2.interleaving2 = userSettings.value("interleaving2").toBool();
			settings->output.video.mpeg2.vdelay = userSettings.value("vdelay").toInt();
			settings->output.video.mpeg2.adelay = userSettings.value("adelay").toInt();
			settings->output.video.mpeg2.drop = userSettings.value("drop").toBool();
			settings->output.video.mpeg2.vbuf_size = userSettings.value("vbuf_size").toInt();
			settings->output.video.mpeg2.abuf_size = userSettings.value("abuf_size").toInt();
			settings->output.video.mpeg2.vpswidth = userSettings.value("vpswidth").toInt();
			settings->output.video.mpeg2.vpsheight = userSettings.value("vpsheight").toInt();
			settings->output.video.mpeg2.telecine = userSettings.value("telecine").toBool();
			settings->output.video.mpeg2.film2pal = userSettings.value("film2pal").toBool();
			settings->output.video.mpeg2.tele_src = userSettings.value("tele_src").toDouble();
			settings->output.video.mpeg2.tele_dest = userSettings.value("tele_dest").toDouble();

			settings->output.video.user_defined.mpeg2.resX = userSettings.value("user defined width").toInt();
			settings->output.video.user_defined.mpeg2.resY = userSettings.value("user defined height").toInt();

			userSettings.endGroup();  // mpeg2
		}

		// Xvid settings (ensure setting exists to avoid insane Xvid parameters)
		if ( userSettings.contains("xvid/resX") )
		{
			userSettings.beginGroup("xvid");

			settings->output.video.xvid.resX = userSettings.value("resX").toInt();
			settings->output.video.xvid.resY = userSettings.value("resY").toInt();
			settings->output.video.xvid.fps = userSettings.value("fps").toDouble();
			settings->output.video.xvid.fourcc = userSettings.value("fourcc").toString();
			settings->output.video.xvid.pass = userSettings.value("pass").toInt();
			settings->output.video.xvid.method = userSettings.value("method").toInt();
			settings->output.video.xvid.bitrate = userSettings.value("bitrate").toInt();
			settings->output.video.xvid.split.size = userSettings.value("split size").toInt();
			settings->output.video.xvid.split.volumes = userSettings.value("split volumes").toInt();
			settings->output.video.xvid.fixed_quant = userSettings.value("fixed_quant").toInt();
			settings->output.video.xvid.vhq = userSettings.value("vhq").toInt();
			settings->output.video.xvid.bvhq = userSettings.value("bvhq").toBool();
			settings->output.video.xvid.max_bframes = userSettings.value("max_bframes").toInt();
			settings->output.video.xvid.bquant_ratio = userSettings.value("bquant_ratio").toInt();
			settings->output.video.xvid.bquant_offset = userSettings.value("bquant_offset").toInt();
			settings->output.video.xvid.trellis = userSettings.value("trellis").toBool();
			settings->output.video.xvid.hq_ac = userSettings.value("hq_ac").toBool();
			settings->output.video.xvid.cartoon = userSettings.value("cartoon").toBool();
			settings->output.video.xvid.me_quality = userSettings.value("me_quality").toInt();
			settings->output.video.xvid.chroma_me = userSettings.value("chroma_me").toBool();
			settings->output.video.xvid.chroma_opt = userSettings.value("chroma_opt").toBool();
			settings->output.video.xvid.lumi_mask = userSettings.value("lumi_mask").toBool();
			settings->output.video.xvid.qpel = userSettings.value("qpel").toBool();
			settings->output.video.xvid.gmc = userSettings.value("gmc").toBool();
			settings->output.video.xvid.quant_type = userSettings.value("quant_type").toInt();
			settings->output.video.xvid.interlacing = userSettings.value("interlacing").toBool();
			settings->output.video.xvid.preset = userSettings.value("preset").toInt();
			settings->output.video.xvid.profile = userSettings.value("profile").toInt();
			settings->output.video.xvid.turbo = userSettings.value("turbo").toBool();

			settings->output.video.user_defined.xvid.resX = userSettings.value("user defined width").toInt();
			settings->output.video.user_defined.xvid.resY = userSettings.value("user defined height").toInt();
			settings->output.video.user_defined.xvid.fps = userSettings.value("user defined fps").toDouble();
			settings->output.video.user_defined.xvid.split.size = userSettings.value("user defined split size").toInt();
			settings->output.video.user_defined.xvid.split.volumes = userSettings.value("user defined split volumes").toInt();
			settings->output.video.user_defined.xvid.profile_set = userSettings.value("user defined profile set").toInt();

			userSettings.endGroup();  // xvid
		}

		// x264 settings (ensure setting exists to avoid insane x264 parameters)
		if ( userSettings.contains("x264/resX") )
		{
			userSettings.beginGroup("x264");

			settings->output.video.x264.resX = userSettings.value("resX").toInt();
			settings->output.video.x264.resY = userSettings.value("resY").toInt();
			settings->output.video.x264.fps = userSettings.value("fps").toDouble();
			settings->output.video.x264.preset = userSettings.value("preset").toInt();
			settings->output.video.x264.profile = userSettings.value("profile").toInt();
			settings->output.video.x264.tune = userSettings.value("tune").toDouble();
			settings->output.video.x264.ratecontrole_qp = userSettings.value("ratecontrole_qp").toInt();
			settings->output.video.x264.ratecontrole_bitrate = userSettings.value("ratecontrole_bitrate").toInt();
			settings->output.video.x264.ratecontrole_crf = userSettings.value("ratecontrole_crf").toDouble();
			settings->output.video.x264.ratecontrole_rc_lookahead = userSettings.value("ratecontrole_rc_lookahead").toInt();
			settings->output.video.x264.ratecontrole_vbv_maxrate = userSettings.value("ratecontrole_vbv_maxrate").toInt();
			settings->output.video.x264.ratecontrole_vbv_bufsize = userSettings.value("ratecontrole_vbv_bufsize").toInt();
			settings->output.video.x264.ratecontrole_vbv_init = userSettings.value("ratecontrole_vbv_init").toDouble();
			settings->output.video.x264.ratecontrole_qpmin = userSettings.value("ratecontrole_qpmin").toInt();
			settings->output.video.x264.ratecontrole_qpmax = userSettings.value("ratecontrole_qpmax").toInt();
			settings->output.video.x264.ratecontrole_qpstep = userSettings.value("ratecontrole_qpstep").toInt();
			settings->output.video.x264.ratecontrole_ratetol = userSettings.value("ratecontrole_ratetol").toDouble();
			settings->output.video.x264.ratecontrole_ipratio = userSettings.value("ratecontrole_ipratio").toDouble();
			settings->output.video.x264.ratecontrole_pbratio = userSettings.value("ratecontrole_pbratio").toDouble();
			settings->output.video.x264.ratecontrole_chroma_qp_offset = userSettings.value("ratecontrole_chroma_qp_offset").toInt();
			settings->output.video.x264.ratecontrole_aq_mode = userSettings.value("ratecontrole_aq_mode").toInt();
			settings->output.video.x264.ratecontrole_aq_strength = userSettings.value("ratecontrole_aq_strength").toDouble();
			settings->output.video.x264.ratecontrole_pass = userSettings.value("ratecontrole_pass").toInt();
			settings->output.video.x264.ratecontrole_no_mbtree = userSettings.value("ratecontrole_no_mbtree").toBool();
			settings->output.video.x264.ratecontrole_stats = userSettings.value("ratecontrole_stats").toString();
			settings->output.video.x264.ratecontrole_qcomp = userSettings.value("ratecontrole_qcomp").toDouble();
			settings->output.video.x264.ratecontrole_cplxblur = userSettings.value("ratecontrole_cplxblur").toDouble();
			settings->output.video.x264.ratecontrole_qblur = userSettings.value("ratecontrole_qblur").toDouble();
			settings->output.video.x264.frametype_keyint = userSettings.value("frametype_keyint").toInt();
			settings->output.video.x264.frametype_min_keyint = userSettings.value("frametype_min_keyint").toInt();
			settings->output.video.x264.frametype_scenecut = userSettings.value("frametype_scenecut").toInt();
			settings->output.video.x264.frametype_bframes = userSettings.value("frametype_bframes").toInt();
			settings->output.video.x264.frametype_b_adapt = userSettings.value("frametype_b_adapt").toInt();
			settings->output.video.x264.frametype_b_bias = userSettings.value("frametype_b_bias").toInt();
			settings->output.video.x264.frametype_b_pyramid = userSettings.value("frametype_b_pyramid").toBool();
			settings->output.video.x264.frametype_no_cabac = userSettings.value("frametype_no_cabac").toBool();
			settings->output.video.x264.frametype_ref = userSettings.value("frametype_ref").toInt();
			settings->output.video.x264.frametype_no_deblock = userSettings.value("frametype_no_deblock").toBool();
			settings->output.video.x264.frametype_deblock_alpha = userSettings.value("frametype_deblock_alpha").toInt();
			settings->output.video.x264.frametype_deblock_beta = userSettings.value("frametype_deblock_beta").toInt();
			settings->output.video.x264.frametype_interlaced = userSettings.value("frametype_interlaced").toBool();
			settings->output.video.x264.analysis_partitions = userSettings.value("analysis_partitions").toString();
			settings->output.video.x264.analysis_direct = userSettings.value("analysis_direct").toString();
			settings->output.video.x264.analysis_no_weightb = userSettings.value("analysis_no_weightb").toBool();
			settings->output.video.x264.analysis_me = userSettings.value("analysis_me").toString();
			settings->output.video.x264.analysis_merange = userSettings.value("analysis_merange").toInt();
			settings->output.video.x264.analysis_mvrange = userSettings.value("analysis_mvrange").toInt();
			settings->output.video.x264.analysis_mvrange_thread = userSettings.value("analysis_mvrange_thread").toInt();
			settings->output.video.x264.analysis_subme = userSettings.value("analysis_subme").toInt();
			settings->output.video.x264.analysis_no_mixed_refs = userSettings.value("analysis_no_mixed_refs").toBool();
			settings->output.video.x264.analysis_no_chroma_me = userSettings.value("analysis_no_chroma_me").toBool();
			settings->output.video.x264.analysis_no_8x8dct = userSettings.value("analysis_no_8x8dct").toBool();
			settings->output.video.x264.analysis_trellis = userSettings.value("analysis_trellis").toInt();
			settings->output.video.x264.analysis_no_fast_pskip = userSettings.value("analysis_no_fast_pskip").toBool();
			settings->output.video.x264.analysis_no_dct_decimate = userSettings.value("analysis_no_dct_decimate").toBool();
			settings->output.video.x264.analysis_nr = userSettings.value("analysis_nr").toInt();
			settings->output.video.x264.analysis_no_psy = userSettings.value("analysis_no_psy").toBool();
			settings->output.video.x264.analysis_psy_rdo = userSettings.value("analysis_psy_rdo").toDouble();
			settings->output.video.x264.analysis_psy_trellis = userSettings.value("analysis_psy_trellis").toDouble();
			settings->output.video.x264.analysis_deadzone_inter = userSettings.value("analysis_deadzone_inter").toInt();
			settings->output.video.x264.analysis_deadzone_intra = userSettings.value("analysis_deadzone_intra").toInt();
			settings->output.video.x264.analysis_cqm = userSettings.value("analysis_cqm").toString();
			settings->output.video.x264.analysis_cqmfile = userSettings.value("analysis_cqmfile").toString();
			settings->output.video.x264.analysis_cqm4 = userSettings.value("analysis_cqm4").toString();
			settings->output.video.x264.analysis_cqm8 = userSettings.value("analysis_cqm8").toString();
			settings->output.video.x264.usability_overscan = userSettings.value("usability_overscan").toString();
			settings->output.video.x264.usability_videoformat = userSettings.value("usability_videoformat").toString();
			settings->output.video.x264.usability_fullrange = userSettings.value("usability_fullrange").toString();
			settings->output.video.x264.usability_colorprim = userSettings.value("usability_colorprim").toString();
			settings->output.video.x264.usability_transfer = userSettings.value("usability_transfer").toString();
			settings->output.video.x264.usability_colormatrix = userSettings.value("usability_colormatrix").toString();
			settings->output.video.x264.usability_chromaloc = userSettings.value("usability_chromaloc").toString();

			settings->output.video.user_defined.x264.resX = userSettings.value("user defined width").toInt();
			settings->output.video.user_defined.x264.resY = userSettings.value("user defined height").toInt();
			settings->output.video.user_defined.x264.fps = userSettings.value("user defined fps").toDouble();

			userSettings.endGroup();  // x264
		}

		userSettings.endGroup();  // Video Settings

		userSettings.beginGroup("Audio Settings");

		settings->output.audio.codec = userSettings.value("codec").toString();

		// Audio filters
		if ( userSettings.contains("filter/volume") )
		{
			userSettings.beginGroup("filter");

			settings->output.audio.filter.volume = userSettings.value("volume").toInt();
			settings->output.audio.filter.sampling = userSettings.value("sampling").toInt();

			userSettings.endGroup();  // filter
		}

		// MP2 settings 
		if ( userSettings.contains("mp2/bitrate") )
		{
			userSettings.beginGroup("mp2");

			settings->output.audio.mp2.srate = userSettings.value("srate").toInt();
			settings->output.audio.mp2.bitrate = userSettings.value("bitrate").toInt();
			settings->output.audio.mp2.vbr = userSettings.value("vbr").toInt();
			settings->output.audio.mp2.maxvbr = userSettings.value("maxvbr").toInt();
			settings->output.audio.mp2.stereo = userSettings.value("stereo").toInt();
			settings->output.audio.mp2.psy = userSettings.value("psy").toInt();

			userSettings.endGroup();  // mp2
		}

		// MP3 settings 
		if ( userSettings.contains("mp3/bitrate") )
		{
			userSettings.beginGroup("mp3");

			settings->output.audio.mp3.srate = userSettings.value("srate").toInt();
			settings->output.audio.mp3.bitrate = userSettings.value("bitrate").toInt();
			settings->output.audio.mp3.method = userSettings.value("method").toInt();
			settings->output.audio.mp3.vbr_q = userSettings.value("vbr_q").toInt();
			settings->output.audio.mp3.vbr_aq = userSettings.value("vbr_aq").toInt();
			settings->output.audio.mp3.ratio = userSettings.value("ratio").toInt();
			settings->output.audio.mp3.stereo = userSettings.value("stereo").toInt();
			settings->output.audio.mp3.padding = userSettings.value("padding").toInt();
			settings->output.audio.mp3.cbr = userSettings.value("cbr").toBool();
			settings->output.audio.mp3.fast = userSettings.value("fast").toBool();
			settings->output.audio.mp3.highpass = userSettings.value("highpass").toInt();
			settings->output.audio.mp3.lowpass = userSettings.value("lowpass").toInt();
			settings->output.audio.mp3.preset = userSettings.value("preset").toString();

			userSettings.endGroup();  // mp3
		}

		// MP4 settings 
		if ( userSettings.contains("mp4/bitrate") )
		{
			userSettings.beginGroup("mp4");

			settings->output.audio.mp4.srate = userSettings.value("srate").toInt();
			settings->output.audio.mp4.bitrate = userSettings.value("bitrate").toInt();
			settings->output.audio.mp4.quality = userSettings.value("quality").toInt();
			settings->output.audio.mp4.object = userSettings.value("object").toInt();
			settings->output.audio.mp4.mpeg = userSettings.value("mpeg").toInt();
			settings->output.audio.mp4.tns = userSettings.value("tns").toBool();
			settings->output.audio.mp4.cutoff = userSettings.value("cutoff").toInt();
			settings->output.audio.mp4.raw = userSettings.value("raw").toBool();

			userSettings.endGroup();  // mp4
		}

		userSettings.endGroup();  // Audio Settings
		userSettings.endGroup();  // Mencoder
	}
*/
	userSettings.endGroup();  // Encoder Settings

	userSettings.endGroup();  // Encoder
}

void Encoder::writeSettings()
{
	QSettings userSettings(appOrganization, appApplication);

	// Encoder
	userSettings.beginGroup("Encoder");
	
	userSettings.setValue("target ext", outputFile->ext);
	userSettings.setValue("target muxer", outputFile->muxer);
	//userSettings.setValue("custom split size", outputFile->split.size);
	//userSettings.setValue("custom split volumes", outputFile->split.volumes);
	
	// Encoder/Engines Settings
	userSettings.beginGroup("Engine Preferences");

/*experimental
	// Encoder/Engines Mencoder
	userSettings.setValue("MEncoder/deinterlacer", preferences.mencoder->deinterlacer);
*/
	userSettings.endGroup();  // Engines

	// Encoder Settings
	userSettings.beginGroup("Encoder Settings");
/*experimental
	if ( engine == Video::Encoder::MEncoder )
	{	
		// MEncoder Settings
		userSettings.beginGroup("MEncoder");

		// MEncoder/Video Settings
		userSettings.beginGroup("Video Settings");

		userSettings.setValue("codec", settings->output.video.codec);

		// MEncoder/Video Settings/filter
		userSettings.beginGroup("filter");

		userSettings.setValue("harddup", settings->output.video.filter.harddup);
		userSettings.setValue("noskip", settings->output.video.filter.noskip);

		userSettings.endGroup();  // filter

		// MEncoder/Video Settings/mpeg1
		userSettings.beginGroup("mpeg1");

		userSettings.setValue("resX", settings->output.video.mpeg1.resX);
		userSettings.setValue("resY", settings->output.video.mpeg1.resY);
		userSettings.setValue("mpeg_fps", settings->output.video.mpeg1.mpeg_fps);
		userSettings.setValue("bitrate", settings->output.video.mpeg1.bitrate);
		userSettings.setValue("stream", settings->output.video.mpeg1.stream);
		userSettings.setValue("pack_size", settings->output.video.mpeg1.pack_size);
		userSettings.setValue("muxrate", settings->output.video.mpeg1.muxrate);
		userSettings.setValue("interleaving2", settings->output.video.mpeg1.interleaving2);
		userSettings.setValue("vdelay", settings->output.video.mpeg1.vdelay);
		userSettings.setValue("adelay", settings->output.video.mpeg1.adelay);
		userSettings.setValue("drop", settings->output.video.mpeg1.drop);
		userSettings.setValue("vbuf_size", settings->output.video.mpeg1.vbuf_size);
		userSettings.setValue("abuf_size", settings->output.video.mpeg1.abuf_size);
		userSettings.setValue("cbr", settings->output.video.mpeg1.cbr);
		userSettings.setValue("minvbr", settings->output.video.mpeg1.minvbr);
		userSettings.setValue("maxvbr", settings->output.video.mpeg1.maxvbr);
		userSettings.setValue("gop_size", settings->output.video.mpeg1.gop_size);
		userSettings.setValue("closed_gop", settings->output.video.mpeg1.closed_gop);
		userSettings.setValue("letter_box", settings->output.video.mpeg1.letter_box);
		userSettings.setValue("force_vcd", settings->output.video.mpeg1.force_vcd);

		userSettings.setValue("user defined width", settings->output.video.user_defined.mpeg1.resX);
		userSettings.setValue("user defined height", settings->output.video.user_defined.mpeg1.resY);

		userSettings.endGroup();  // mpeg1

		// MEncoder/Video Settings/mpeg2
		userSettings.beginGroup("mpeg2");

		userSettings.setValue("resX", settings->output.video.mpeg2.resX);
		userSettings.setValue("resY", settings->output.video.mpeg2.resY);
		userSettings.setValue("mpeg_aspect", settings->output.video.mpeg2.mpeg_aspect);
		userSettings.setValue("mpeg_fps", settings->output.video.mpeg2.mpeg_fps);
		userSettings.setValue("bitrate", settings->output.video.mpeg2.bitrate);
		userSettings.setValue("stream", settings->output.video.mpeg2.stream);
		userSettings.setValue("pack_size", settings->output.video.mpeg2.pack_size);
		userSettings.setValue("muxrate", settings->output.video.mpeg2.muxrate);
		userSettings.setValue("tsaf", settings->output.video.mpeg2.tsaf);
		userSettings.setValue("interleaving2", settings->output.video.mpeg2.interleaving2);
		userSettings.setValue("vdelay", settings->output.video.mpeg2.vdelay);
		userSettings.setValue("adelay", settings->output.video.mpeg2.adelay);
		userSettings.setValue("drop", settings->output.video.mpeg2.drop);
		userSettings.setValue("vbuf_size", settings->output.video.mpeg2.vbuf_size);
		userSettings.setValue("abuf_size", settings->output.video.mpeg2.abuf_size);
		userSettings.setValue("vpswidth", settings->output.video.mpeg2.vpswidth);
		userSettings.setValue("vpsheight", settings->output.video.mpeg2.vpsheight);
		userSettings.setValue("telecine", settings->output.video.mpeg2.telecine);
		userSettings.setValue("film2pal", settings->output.video.mpeg2.film2pal);
		userSettings.setValue("tele_src", settings->output.video.mpeg2.tele_src);
		userSettings.setValue("tele_dest", settings->output.video.mpeg2.tele_dest);

		userSettings.setValue("user defined width", settings->output.video.user_defined.mpeg2.resX);
		userSettings.setValue("user defined height", settings->output.video.user_defined.mpeg2.resY);

		userSettings.endGroup();  // mpeg2

		// MEncoder/Video Settings/xvid
		userSettings.beginGroup("xvid");

		userSettings.setValue("resX", settings->output.video.xvid.resX);
		userSettings.setValue("resY", settings->output.video.xvid.resY);
		userSettings.setValue("fps", settings->output.video.xvid.fps);
		userSettings.setValue("fourcc", settings->output.video.xvid.fourcc);
		userSettings.setValue("pass", settings->output.video.xvid.pass);
		userSettings.setValue("method", settings->output.video.xvid.method);
		userSettings.setValue("bitrate", settings->output.video.xvid.bitrate);
		userSettings.setValue("split size", settings->output.video.xvid.split.size);
		userSettings.setValue("split volumes", settings->output.video.xvid.split.volumes);
		userSettings.setValue("fixed_quant", settings->output.video.xvid.fixed_quant);
		userSettings.setValue("vhq", settings->output.video.xvid.vhq);
		userSettings.setValue("bvhq", settings->output.video.xvid.bvhq);
		userSettings.setValue("max_bframes", settings->output.video.xvid.max_bframes);
		userSettings.setValue("bquant_ratio", settings->output.video.xvid.bquant_ratio);
		userSettings.setValue("bquant_offset", settings->output.video.xvid.bquant_offset);
		userSettings.setValue("trellis", settings->output.video.xvid.trellis);
		userSettings.setValue("hq_ac", settings->output.video.xvid.hq_ac);
		userSettings.setValue("cartoon", settings->output.video.xvid.cartoon);
		userSettings.setValue("me_quality", settings->output.video.xvid.me_quality);
		userSettings.setValue("chroma_me", settings->output.video.xvid.chroma_me);
		userSettings.setValue("chroma_opt", settings->output.video.xvid.chroma_opt);
		userSettings.setValue("lumi_mask", settings->output.video.xvid.lumi_mask);
		userSettings.setValue("qpel", settings->output.video.xvid.qpel);
		userSettings.setValue("gmc", settings->output.video.xvid.gmc);
		userSettings.setValue("quant_type", settings->output.video.xvid.quant_type);
		userSettings.setValue("interlacing", settings->output.video.xvid.interlacing);
		userSettings.setValue("preset", settings->output.video.xvid.preset);
		userSettings.setValue("profile", settings->output.video.xvid.profile);
		userSettings.setValue("turbo", settings->output.video.xvid.turbo);
	
		userSettings.setValue("user defined width", settings->output.video.user_defined.xvid.resX);
		userSettings.setValue("user defined height", settings->output.video.user_defined.xvid.resY);
		userSettings.setValue("user defined fps", settings->output.video.user_defined.xvid.fps);
		userSettings.setValue("user defined split size", settings->output.video.user_defined.xvid.split.size);
		userSettings.setValue("user defined split volumes", settings->output.video.user_defined.xvid.split.volumes);
		userSettings.setValue("user defined profile set", settings->output.video.user_defined.xvid.profile_set);

		userSettings.endGroup();  // xvid

		// MEncoder/Video Settings/x264
		userSettings.beginGroup("x264");

		userSettings.setValue("resX", settings->output.video.x264.resX);
		userSettings.setValue("resY", settings->output.video.x264.resY);
		userSettings.setValue("fps", settings->output.video.x264.fps);
		userSettings.setValue("preset", settings->output.video.x264.preset);
		userSettings.setValue("profile", settings->output.video.x264.profile);
		userSettings.setValue("tune", settings->output.video.x264.tune);
		userSettings.setValue("ratecontrole_qp", settings->output.video.x264.ratecontrole_qp);
		userSettings.setValue("ratecontrole_bitrate", settings->output.video.x264.ratecontrole_bitrate);
		userSettings.setValue("ratecontrole_crf", settings->output.video.x264.ratecontrole_crf);
		userSettings.setValue("ratecontrole_rc_lookahead", settings->output.video.x264.ratecontrole_rc_lookahead);
		userSettings.setValue("ratecontrole_vbv_maxrate", settings->output.video.x264.ratecontrole_vbv_maxrate);
		userSettings.setValue("ratecontrole_vbv_bufsize", settings->output.video.x264.ratecontrole_vbv_bufsize);
		userSettings.setValue("ratecontrole_vbv_init", settings->output.video.x264.ratecontrole_vbv_init);
		userSettings.setValue("ratecontrole_qpmin", settings->output.video.x264.ratecontrole_qpmin);
		userSettings.setValue("ratecontrole_qpmax", settings->output.video.x264.ratecontrole_qpmax);
		userSettings.setValue("ratecontrole_qpstep", settings->output.video.x264.ratecontrole_qpstep);
		userSettings.setValue("ratecontrole_ratetol", settings->output.video.x264.ratecontrole_ratetol);
		userSettings.setValue("ratecontrole_ipratio", settings->output.video.x264.ratecontrole_ipratio);
		userSettings.setValue("ratecontrole_pbratio", settings->output.video.x264.ratecontrole_pbratio);
		userSettings.setValue("ratecontrole_chroma_qp_offset", settings->output.video.x264.ratecontrole_chroma_qp_offset);
		userSettings.setValue("ratecontrole_aq_mode", settings->output.video.x264.ratecontrole_aq_mode);
		userSettings.setValue("ratecontrole_aq_strength", settings->output.video.x264.ratecontrole_aq_strength);
		userSettings.setValue("ratecontrole_pass", settings->output.video.x264.ratecontrole_pass);
		userSettings.setValue("ratecontrole_no_mbtree", settings->output.video.x264.ratecontrole_no_mbtree);
		userSettings.setValue("ratecontrole_stats", settings->output.video.x264.ratecontrole_stats);
		userSettings.setValue("ratecontrole_qcomp", settings->output.video.x264.ratecontrole_qcomp);
		userSettings.setValue("ratecontrole_cplxblur", settings->output.video.x264.ratecontrole_cplxblur);
		userSettings.setValue("ratecontrole_qblur", settings->output.video.x264.ratecontrole_qblur);
		userSettings.setValue("frametype_keyint", settings->output.video.x264.frametype_keyint);
		userSettings.setValue("frametype_min_keyint", settings->output.video.x264.frametype_min_keyint);
		userSettings.setValue("frametype_scenecut", settings->output.video.x264.frametype_scenecut);
		userSettings.setValue("frametype_bframes", settings->output.video.x264.frametype_bframes);
		userSettings.setValue("frametype_b_adapt", settings->output.video.x264.frametype_b_adapt);
		userSettings.setValue("frametype_b_bias", settings->output.video.x264.frametype_b_bias);
		userSettings.setValue("frametype_b_pyramid", settings->output.video.x264.frametype_b_pyramid);
		userSettings.setValue("frametype_no_cabac", settings->output.video.x264.frametype_no_cabac);
		userSettings.setValue("frametype_ref", settings->output.video.x264.frametype_ref);
		userSettings.setValue("frametype_no_deblock", settings->output.video.x264.frametype_no_deblock);
		userSettings.setValue("frametype_deblock_alpha", settings->output.video.x264.frametype_deblock_alpha);
		userSettings.setValue("frametype_deblock_beta", settings->output.video.x264.frametype_deblock_beta);
		userSettings.setValue("frametype_interlaced", settings->output.video.x264.frametype_interlaced);
		userSettings.setValue("analysis_partitions", settings->output.video.x264.analysis_partitions);
		userSettings.setValue("analysis_direct", settings->output.video.x264.analysis_direct);
		userSettings.setValue("analysis_no_weightb", settings->output.video.x264.analysis_no_weightb);
		userSettings.setValue("analysis_me", settings->output.video.x264.analysis_me);
		userSettings.setValue("analysis_merange", settings->output.video.x264.analysis_merange);
		userSettings.setValue("analysis_mvrange", settings->output.video.x264.analysis_mvrange);
		userSettings.setValue("analysis_mvrange_thread", settings->output.video.x264.analysis_mvrange_thread);
		userSettings.setValue("analysis_subme", settings->output.video.x264.analysis_subme);
		userSettings.setValue("analysis_no_mixed_refs", settings->output.video.x264.analysis_no_mixed_refs);
		userSettings.setValue("analysis_no_chroma_me", settings->output.video.x264.analysis_no_chroma_me);
		userSettings.setValue("analysis_no_8x8dct", settings->output.video.x264.analysis_no_8x8dct);
		userSettings.setValue("analysis_trellis", settings->output.video.x264.analysis_trellis);
		userSettings.setValue("analysis_no_fast_pskip", settings->output.video.x264.analysis_no_fast_pskip);
		userSettings.setValue("analysis_no_dct_decimate", settings->output.video.x264.analysis_no_dct_decimate);
		userSettings.setValue("analysis_nr", settings->output.video.x264.analysis_nr);
		userSettings.setValue("analysis_no_psy", settings->output.video.x264.analysis_no_psy);
		userSettings.setValue("analysis_psy_rdo", settings->output.video.x264.analysis_psy_rdo);
		userSettings.setValue("analysis_psy_trellis", settings->output.video.x264.analysis_psy_trellis);
		userSettings.setValue("analysis_deadzone_inter", settings->output.video.x264.analysis_deadzone_inter);
		userSettings.setValue("analysis_deadzone_intra", settings->output.video.x264.analysis_deadzone_intra);
		userSettings.setValue("analysis_cqm", settings->output.video.x264.analysis_cqm);
		userSettings.setValue("analysis_cqmfile", settings->output.video.x264.analysis_cqmfile);
		userSettings.setValue("analysis_cqm4", settings->output.video.x264.analysis_cqm4);
		userSettings.setValue("analysis_cqm8", settings->output.video.x264.analysis_cqm8);
		userSettings.setValue("usability_overscan", settings->output.video.x264.usability_overscan);
		userSettings.setValue("usability_videoformat", settings->output.video.x264.usability_videoformat);
		userSettings.setValue("usability_fullrange", settings->output.video.x264.usability_fullrange);
		userSettings.setValue("usability_colorprim", settings->output.video.x264.usability_colorprim);
		userSettings.setValue("usability_transfer", settings->output.video.x264.usability_transfer);
		userSettings.setValue("usability_colormatrix", settings->output.video.x264.usability_colormatrix);
		userSettings.setValue("usability_chromaloc", settings->output.video.x264.usability_chromaloc);

		userSettings.setValue("user defined width", settings->output.video.user_defined.x264.resX);
		userSettings.setValue("user defined height", settings->output.video.user_defined.x264.resY);
		userSettings.setValue("user defined fps", settings->output.video.user_defined.x264.fps);

		userSettings.endGroup();  // x264

		userSettings.endGroup();  // Video Settings

		// MEncoder/Audio Settings
		userSettings.beginGroup("Audio Settings");

		userSettings.setValue("codec", settings->output.audio.codec);

		// MEncoder/Audio Settings/filter
		userSettings.beginGroup("filter");

		userSettings.setValue("volume", settings->output.audio.filter.volume);
		userSettings.setValue("sampling", settings->output.audio.filter.sampling);

		userSettings.endGroup();  // filter

		// MEncoder/Audio Settings/mp2
		userSettings.beginGroup("mp2");
		userSettings.setValue("srate", settings->output.audio.mp2.srate);
		userSettings.setValue("bitrate", settings->output.audio.mp2.bitrate);
		userSettings.setValue("vbr", settings->output.audio.mp2.vbr);
		userSettings.setValue("maxvbr", settings->output.audio.mp2.maxvbr);
		userSettings.setValue("stereo", settings->output.audio.mp2.stereo);
		userSettings.setValue("psy", settings->output.audio.mp2.psy);
		userSettings.endGroup();  // mp2

		// MEncoder/Audio Settings/mp3
		userSettings.beginGroup("mp3");
		userSettings.setValue("srate", settings->output.audio.mp3.srate);
		userSettings.setValue("bitrate", settings->output.audio.mp3.bitrate);
		userSettings.setValue("method", settings->output.audio.mp3.method);
		userSettings.setValue("vbr_q", settings->output.audio.mp3.vbr_q);
		userSettings.setValue("vbr_aq", settings->output.audio.mp3.vbr_aq);
		userSettings.setValue("ratio", settings->output.audio.mp3.ratio);
		userSettings.setValue("stereo", settings->output.audio.mp3.stereo);
		userSettings.setValue("padding", settings->output.audio.mp3.padding);
		userSettings.setValue("cbr", settings->output.audio.mp3.cbr);
		userSettings.setValue("fast", settings->output.audio.mp3.fast);
		userSettings.setValue("highpass", settings->output.audio.mp3.highpass);
		userSettings.setValue("lowpass", settings->output.audio.mp3.lowpass);
		userSettings.setValue("preset", settings->output.audio.mp3.preset);
		userSettings.endGroup();  // mp3

		// MEncoder/Audio Settings/mp4
		userSettings.beginGroup("mp4");
		userSettings.setValue("srate", settings->output.audio.mp4.srate);
		userSettings.setValue("bitrate", settings->output.audio.mp4.bitrate);
		userSettings.setValue("quality", settings->output.audio.mp4.quality);
		userSettings.setValue("object", settings->output.audio.mp4.object);
		userSettings.setValue("mpeg", settings->output.audio.mp4.mpeg);
		userSettings.setValue("tns", settings->output.audio.mp4.tns);
		userSettings.setValue("cutoff", settings->output.audio.mp4.cutoff);
		userSettings.setValue("raw", settings->output.audio.mp4.raw);
		userSettings.endGroup();  // mp4

		userSettings.endGroup();  // Audio Settings
		userSettings.endGroup();  // Mencoder
	}
*/
	userSettings.endGroup();  // Encoder Settings

	userSettings.endGroup();  //Encoder
}

int Encoder::selectConvenientEngine()
{
	int engine(Video::Encoder::FFmpeg);  // default is FFmpeg
	
	// DVD with MEncoder (how about VCD?)
	if (input->source.media == Video::Media::DVD) engine = Video::Encoder::MEncoder;

	// FFmpeg can't ensure DivX Plus HD constraints
	else if (input->video.codec == "x264_divx") engine = Video::Encoder::FFmpeg;

	// MEncoder can't encode audio files
	else if (input->source.media == Video::Media::File
		&& input->video.media == 0) engine = Video::Encoder::FFmpeg;

	// FFmpeg can't encode MPEG-1 input (error: Buffering several frames is not supported.)
	else if (input->source.media == Video::Media::File
		&& input->video.codec == "mpeg1video") engine = Video::Encoder::MEncoder;

	// FFmpeg doesn't write frame rate in MPEG-TS files
	else if (input->source.media == Video::Media::File
		&& !input->no_video && outputFile->muxer == "mpegts") engine = Video::Encoder::MEncoder;
	
	// VCD (MPEG-1) is 4:3 only and FFmpeg fails to resize/letterbox
	else if (outputFile->muxer == "mpeg" || outputFile->muxer == "mpeg_vcd") engine = Video::Encoder::MEncoder;

	/* FFmpeg AAC is "strict-experimental"
	else if (outputFile->muxer == "m4a") engine = Video::Encoder::MEncoder;
	*/

	return engine;
}
