/*****************************************************************************
 *
 *  configurator.cpp -- Guess encoder settings.
 *
 *  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 "configurator.h"
#include "../video/video_constants.h"
#include "../video/video_functions.h"
#include <QDebug>

Configurator::Configurator(Encoder *encoder)
{
	this->encoder = encoder;
	this->inputSettings = encoder->getInputSettings();

	supportedProfiles << Video::Profile::None 
		<< Video::Profile::Low << Video::Profile::Medium << Video::Profile::High
		<< Video::Profile::Copy;

	setVideoProfiles();
	setAudioProfiles();

	profileInterface = new ProfileInterface;
}

int Configurator::readProfileFromSettings(const QString &muxer)
{
	QSettings settings;

	QString lastProfileKey= QString("Encoder/Last Profile/%1").arg(muxer);

	int level = settings.value( lastProfileKey, Video::Profile::None ).toInt();

	if ( !supportedProfiles.contains(level) ) level = Video::Profile::None;

	return level;
}

void Configurator::writeProfileInSettings(const QString &muxer, const int &level)
{
	QSettings settings;

	QString lastProfileKey= QString("Encoder/Last Profile/%1").arg(muxer);

    settings.setValue( lastProfileKey, level );

	settings.sync();
}

void Configurator::save()
{
	QListIterator<Profile> p(profileInterface->profiles);
	while (p.hasNext())
	{
		encoder_profile_t profile = p.next().profile;

		if ( profile.level == profileInterface->selected )
		{
			*(profileInterface->setting) = profile;
			break;
		}
	}

	writeProfileInSettings(encoder->getOutputMuxer(), profileInterface->selected);
}

QSize Configurator::preferredRez43(const QSize &rez)
{
	QSize rez43(rez);

	if (rez.height() >= 1080)  // in case we forget to set 1088 (1080 != 16n)
	{
		rez43 = QSize( 1440, 1088 );
	}
	else if (rez.height() >= 540)
	{
		rez43 = QSize( 720, 544 );
	}
	else if (rez.height() >= 480)
	{
		rez43 = QSize( 640, 480 );
	}
	else if (rez.height() >= 384)
	{
		rez43 = QSize( 512, 384 );
	}
	else if (rez.height() >= 360)
	{
		rez43 = QSize( 480, 360 );
	}
	else if (rez.height() >= 288)
	{
		rez43 = QSize( 384, 288 );
	}
	else if (rez.height() >= 240)
	{
		rez43 = QSize( 320, 240 );
	}

	return rez43;
}

QList<Configurator::Profile> Configurator::getProfileList(const int engine, const QString &muxer,
	const QString &videoCodec, const QString &audioCodec)
{
	QList<Configurator::Profile> profileList;
	Configurator::Profile profile;

	if ( !encoder->isSupportedMuxer(engine, muxer) ) return profileList;

	QString	standard = inputSettings->video.standard;
	if ( standard.isEmpty() )
	{
		standard = inputSettings->video.fps == 25.0 || inputSettings->video.fps == 50.0 ? "PAL" : "NTSC";
	}
	
	QList<encoder_profile_t> profiles;
	QList<int> levels;
	QHash<int, encoder_video_profile_t> videoProfilesByLevel;
	QHash<int, encoder_audio_profile_t> audioProfilesByLevel;

	if ( encoder->isSupportedVideo(engine, muxer, videoCodec) )
	{
		QListIterator<encoder_video_profile_t> vp(profileVideos.values(videoCodec));
		while (vp.hasNext())
		{	
			encoder_video_profile_t profile = vp.next();

			if ( profile.standard.isEmpty() || profile.standard == standard )
			{
				// Set 4:3 profile if necessary (if profile aspect is 16:9 square and input is 4:3)
				double input_aspect = (double)inputSettings->video.scaledRez.width() / (double)inputSettings->video.scaledRez.height();
				double profile_square_aspect = (double)profile.rez.width() / (double)profile.rez.height();

				if ( (profile_square_aspect > 1.75 && profile_square_aspect < 1.79) 
					&& (input_aspect > 1.31 && input_aspect < 1.35) )
				{
					profile.rez = preferredRez43(profile.rez);
				}
				
				videoProfilesByLevel.insert(profile.level, profile);
					
				if (!levels.contains(profile.level)) levels.append(profile.level);
			}
		}
	}

	if ( encoder->isSupportedAudio(engine, muxer, audioCodec) )
	{
		QListIterator<encoder_audio_profile_t> ap(profileAudios.values(audioCodec));
		while (ap.hasNext())
		{	
			encoder_audio_profile_t profile = ap.next();

			if (profile.level == Video::Profile::Copy && audioCodec != inputSettings->audio.codec) continue;
			
			audioProfilesByLevel.insert(profile.level, profile);

			if (!levels.contains(profile.level)) levels.append(profile.level);
		}
	}

	qSort(levels.begin(), levels.end());

	encoder_profile_t workingProfile;
	workingProfile.muxer = muxer;
	workingProfile.standard = standard;

	QListIterator<int> i(levels);
	while (i.hasNext())
	{
		workingProfile.level = i.next();

		if ( videoProfilesByLevel.contains(workingProfile.level) )
		{
			workingProfile.video.codec = videoProfilesByLevel[workingProfile.level].codec;
			workingProfile.video.rez = videoProfilesByLevel[workingProfile.level].rez;
			workingProfile.video.bitrate = videoProfilesByLevel[workingProfile.level].bitrate;
		}
		else
		{
			workingProfile.video.codec.clear();  // no video in this profile
		}

		if ( audioProfilesByLevel.contains(workingProfile.level) )
		{
			workingProfile.audio.codec = audioProfilesByLevel[workingProfile.level].codec;
			workingProfile.audio.sampling = audioProfilesByLevel[workingProfile.level].sampling;
			workingProfile.audio.bitrate = audioProfilesByLevel[workingProfile.level].bitrate;
		}
		else
		{
			workingProfile.audio.codec.clear();  // no audio in this profile
		}

		profiles.append(workingProfile);
	}

	if ( profiles.isEmpty() ) return profileList;

	QListIterator<encoder_profile_t> p(profiles);
	while (p.hasNext())
	{
		profile.profile = p.next();

		profile.level = profile.profile.level;
		profile.title = getProfileTitle(&profile.profile);
		profile.description = encoder->profileDescription(&profile.profile);
		profileList.append( profile );
	}
	
	return profileList;
}

bool Configurator::isValidProfile(const QString &muxer,
	const QString &videoCodec, const QString &audioCodec, const int level)
{
	bool foundVideo(videoCodec == "novideo"), foundAudio(audioCodec == "noaudio");

	QHashIterator<QString, encoder_video_profile_t> vp(profileVideos);
	while (vp.hasNext())
	{
		vp.next();

		if (vp.value().codec != videoCodec) continue;

		if (vp.value().level == level) 
		{
			foundVideo = true;
			break; 
		}
	}

	if (!foundVideo) return false;
	
	QHashIterator<QString, encoder_audio_profile_t> ap(profileAudios);
	while (ap.hasNext())
	{
		ap.next();

		if (ap.value().codec != audioCodec) continue;

		if (ap.value().level == level) 
		{
			foundAudio = true;
			break; 
		}
	}

	return foundAudio;
}

encoder_profile_t Configurator::getProfile(const QString &muxer,
	const QString &videoCodec, const QString &audioCodec, const int level)
{
	QString standard = inputSettings->video.standard;
	if ( standard.isEmpty() )
	{
		standard = inputSettings->video.fps == 25.0 || inputSettings->video.fps == 50.0 ? "PAL" : "NTSC";
	}

	encoder_profile_t profile;
	encoder_video_profile_t videoProfile, videoProfileGeneric;
	encoder_audio_profile_t audioProfile;

	QList<encoder_video_profile_t> videoProfiles;
	QList<encoder_audio_profile_t> audioProfiles;

	if (profileVideos.contains(videoCodec)) videoProfiles = profileVideos.values(videoCodec);
	if (profileAudios.contains(audioCodec)) audioProfiles = profileAudios.values(audioCodec);

	QListIterator<encoder_video_profile_t> vp(videoProfiles);
	while (vp.hasNext())
	{
		encoder_video_profile_t vProfile = vp.next();

		if (vProfile.level == level && vProfile.standard == standard) 
		{		
			videoProfile = vProfile;
		}
		else if (vProfile.level == level && vProfile.standard.isEmpty()) 
		{		
			videoProfileGeneric = vProfile;
		}
	}

	if (videoProfile.codec.isEmpty() && !videoProfileGeneric.codec.isEmpty())
	{
		videoProfile = videoProfileGeneric;
	}

	QListIterator<encoder_audio_profile_t> ap(audioProfiles);
	while (ap.hasNext())
	{
		audioProfile = ap.next();

		if (audioProfile.level == level) break;  // found audio profile 
	}

	profile.muxer = muxer;
	profile.level = level;
	profile.standard = standard;
	profile.video.codec = videoProfile.codec;
	profile.video.rez = videoProfile.rez;
	profile.video.bitrate = videoProfile.bitrate;
	profile.audio.codec = audioProfile.codec;
	profile.audio.sampling = audioProfile.sampling;
	profile.audio.bitrate = audioProfile.bitrate;

	// Set 4:3 profile if necessary (if profile aspect is 16:9 square and input is 4:3)
	double input_aspect = (double)inputSettings->video.scaledRez.width() / (double)inputSettings->video.scaledRez.height();
	double profile_square_aspect = (double)profile.video.rez.width() / (double)profile.video.rez.height();

	if ( (profile_square_aspect > 1.75 && profile_square_aspect < 1.79) 
		&& (input_aspect > 1.31 && input_aspect < 1.35) )
	{
		profile.video.rez = preferredRez43(videoProfile.rez);
	}

	return profile;  // found or empty
}

bool Configurator::guessUserInterface()
{
	QString muxer = encoder->getOutputMuxer();
	QString video = encoder->getOutputVideoCodec();
	QString audio = encoder->getOutputAudioCodec();

	int engine = encoder->selectConvenientEngine();

	return configure(engine, muxer, video, audio);
}

bool Configurator::configure(const int engine, const QString &muxer, 
	const QString &videoCodec, const QString &audioCodec)
{
	encoder_settings_t *settings = encoder->getSettings(engine);
	int profileLevel = readProfileFromSettings(muxer);

	profileInterface->title = encoder->muxerName(muxer);
	
	profileInterface->panelTitle = tr("Profile");
	profileInterface->setting = &settings->output.profile;
	profileInterface->profiles = getProfileList(engine, muxer, videoCodec, audioCodec);

	if ( profileInterface->profiles.isEmpty() ) return false;

	if ( profileLevel == Video::Profile::None 
		|| !supportedProfiles.contains(profileLevel)
		|| !isValidProfile(muxer, videoCodec, audioCodec, profileLevel)
		|| (muxer == "ac3" && profileLevel == Video::Profile::Copy && inputSettings->audio.codec != audioCodec) )
	{
		settings->output.profile.level = Video::Profile::Medium;
	}
	else if ( inputSettings->source.media == Video::Media::DVD && audioCodec == "ac3" )
	{
		settings->output.profile.level = Video::Profile::Copy;
	}
	else
	{
		settings->output.profile.level = profileLevel;
	}

	profileInterface->selected = settings->output.profile.level;

	writeProfileInSettings(muxer, settings->output.profile.level);
	return true;
}

QStringList Configurator::getApplicableMuxers()
{
	QStringList codes;

	if ( encoder->isReady() ) codes.append( getSupportedProfileMuxers() );

	if (inputSettings->source.media == Video::Media::DVD)
	{
		codes.removeAll("ipod");
		codes.removeAll("m4a");
		codes.removeAll("mov");
	}

	return codes;
}

QStringList Configurator::getApplicableVideos(const QString &muxer)
{
	QStringList codes;

	if (inputSettings->no_video)
	{
		return QStringList( "novideo" );
	}
	else
	{
		if ( encoder->isReady() ) codes.append( getSupportedProfileVideoCodecs(muxer) );
	}

	//*experimental MEncoder/FFmpeg not ready yet for these formats
	codes.removeAll("x264_divx");

	if ( codes.isEmpty() ) codes.append( "novideo" );

	return codes;
}

QStringList Configurator::getApplicableAudios(const QString &muxer)
{
	QStringList codes;

	int audioN = encoder->getAudioInputCount();

	if (audioN == 0 || inputSettings->no_audio)
	{
		codes.append( "noaudio" );
	}
	else if (audioN > 1)
	{
		codes.append( "multi" );
	}
	else
	{
		if ( encoder->isReady() ) codes.append( getSupportedProfileAudioCodecs(muxer) );
	}

	if (inputSettings->source.media == Video::Media::DVD)
	{
		codes.removeAll("ac3");
		codes.removeAll("alac");
		codes.removeAll("vorbis");

#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
		codes.removeAll("flac");
#endif

		if (muxer == "mp4") codes.removeAll("ac3_copy");
	}

	if (inputSettings->source.media == Video::Media::File)
	{
		codes.removeAll("ac3_copy");
	}

	if ( codes.isEmpty() ) codes.append( "noaudio" );

	return codes;
}

QStringList Configurator::getApplicableSubtitles(const QString &muxer)
{
	QStringList codes;

	int subtitleN = encoder->getSubtitleInputCount();

	if (subtitleN == 0 || inputSettings->no_subtitle)
	{
		codes.append( "nosubtitle" );
	}
	else if (subtitleN > 1)
	{
		codes.append( "multi" );
	}
	else
	{
		codes.append( "inlay" );
	}

	if ( codes.isEmpty() ) codes.append( "nosubtitle" );

	return codes;
}

QStringList Configurator::getSupportedProfileMuxers()
{
	QStringList muxerList;

	QStringList muxers = encoder->supportedMuxers();

	QListIterator<QString> m(muxers);
	while (m.hasNext()) 
	{
		QString muxer = m.next();

		if ( !getSupportedProfileVideoCodecs(muxer).isEmpty()
			|| !getSupportedProfileAudioCodecs(muxer).isEmpty() )
		{
			muxerList.append(muxer);
		}			
	}

	muxerList.removeDuplicates();

	return muxerList;
}

QStringList Configurator::getSupportedProfileVideoCodecs(const QString &muxer)
{
	QStringList codecs;

	QListIterator<QString> c(profileVideos.uniqueKeys());
	while (c.hasNext()) 
	{
		QString codec = c.next();
		if ( encoder->muxerSupportVideo(muxer, codec) ) codecs.append(codec);
	}

	codecs.removeDuplicates();

	// Remove formats not supported by MEncoder
	if ( inputSettings->source.media == Video::Media::DVD )
	{
		// Theora not supported
		codecs.removeAll("theora");
		// WebM, VP8 not supported
		codecs.removeAll("vp8");
	}

	// Remove formats not supported by FFmpeg
	if ( inputSettings->source.media == Video::Media::File )
	{
		// VP8 not supported (unless you're lucky to have a patch for VP8)
#ifdef WIN32
		//codecs.removeAll("vp8");
#endif
	}

	return codecs;
}

QStringList Configurator::getSupportedProfileAudioCodecs(const QString &muxer)
{
	QStringList codecs;
	
	QListIterator<QString> c(profileAudios.uniqueKeys());
	while (c.hasNext()) 
	{
		QString codec = c.next();

		//*experimental PCM not supported for DVD
		if ( inputSettings->source.media == Video::Media::DVD && codec == "pcm" ) continue;

		//*experimental AMR-NB not supported for DVD
		if ( inputSettings->source.media == Video::Media::DVD && codec == "amrnb" ) continue;

#ifdef Q_OS_MAC
		//*experimental AMR-NB not supported by FFmpeg macport
		if ( inputSettings->source.media == Video::Media::File && codec == "amrnb" ) continue;
#endif
		if ( encoder->muxerSupportAudio(muxer, codec) ) codecs.append(codec);
	}

	codecs.removeDuplicates();

	return codecs;
}

QString Configurator::getProfileName(const int level, const QString &standard,
	const QString &muxer, const QString &video, const QString &audio)
{
	QString str;

	if (muxer == "mpeg_vcd" && video == "mpeg1video" && audio == "mp2_vcd")
	{
		if (level == Video::Profile::Medium)	str = "VideoCD";
		else if (level == Video::Profile::High)	str = "eXtended-VCD";
		else if (level == Video::Profile::User)	str = "MPEG-1";
	
		if (!standard.isEmpty()) str+= " (" + standard + ")";
	}
	else if (muxer == "mpeg" && video == "mpeg2video" && audio == "mp2")
	{
		if (level == Video::Profile::Low)			str = "China-VideoCD";
		else if (level == Video::Profile::Medium)	str = "Super-VideoCD";
		else if (level == Video::Profile::High)		str = "DVD-Video";
		else if (level == Video::Profile::User)		str = "MPEG-2";
	
		if (!standard.isEmpty()) str += " (" + standard + ")";
	}
	else if (muxer == "mpeg" && video == "mpeg2video" 
		&& (audio.startsWith("pcm") || audio == "copy") ) // copy only allowed for DVD input
	{
		str = "DVD-Video (DVD)";
	
		if (!standard.isEmpty()) str += " (" + standard + ")";
	}
	else if (muxer == "ac3" 
		&& level == Video::Profile::Copy)
	{
		str = tr("Audio AC3 source copy");
	}
	else
	{
		str = encoder->muxerShortName(muxer) + " " + Video::strProfile(level) + " profile";
	}

	return str;
}

QString Configurator::getProfileTitle(const encoder_profile_t *profile)
{
	QString title;

	if (profile->muxer == "mpeg_vcd" 
		&& profile->video.codec == "mpeg1video" && profile->audio.codec == "mp2_vcd")
	{
		if (profile->level == Video::Profile::Medium)		title = "VideoCD (VCD)";
		else if (profile->level == Video::Profile::High)	title = "eXtended-VCD (XVCD)";
	}
	else if (profile->muxer == "mpeg" 
			&& profile->video.codec == "mpeg2video" && profile->audio.codec == "mp2")
	{
		if (profile->level == Video::Profile::Low)			title = "China Video Disc (CVD/CVCD)";
		else if (profile->level == Video::Profile::Medium)	title = "Super Video Disc (SVCD)";
		else if (profile->level == Video::Profile::High)	title = "DVD-Video (DVD)";
	}
	else if (profile->muxer == "mpeg" && profile->video.codec == "mpeg2video" 
		&& (profile->audio.codec.startsWith("pcm") || profile->audio.codec == "copy") ) // copy only allowed for DVD input
	{
		title = "DVD-Video";
	}
	else if (profile->muxer == "ac3" 
		&& profile->audio.sampling == -1)
	{
		title = tr("Source copy");
	}
	else
	{
		title = Video::strProfileTitle(profile->level);
	}

	return title;
}

void Configurator::setVideoProfiles()
{
	encoder_video_profile_t profile;

	////////////////////////////////////////////////////////////
	// H.263 
	profile.codec = "h263";

	// Notes:
	// H.263+ (SIF) rezolutions aren't supported as decoder by MPlayer or FFplay, so we ignore them

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(128, 96);
	profile.bitrate = 64.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "";
	profile.rez = QSize(176, 144);
	profile.bitrate = 128.0;
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "";
	profile.rez = QSize(352, 288);
	profile.bitrate = 256.0;
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// MPEG-1
	profile.codec = "mpeg1video";

	// Medium (so is default)
	profile.level = Video::Profile::Medium;
	profile.standard = "NTSC";
	profile.rez = QSize(352, 240);
	profile.bitrate = 1152.0;
	profileVideos.insertMulti(profile.codec, profile);

	profile.standard = "PAL";
	profile.rez = QSize(352, 288);
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "NTSC";
	profile.rez = QSize(352, 480);
	profile.bitrate = 2376.0;
	profileVideos.insertMulti(profile.codec, profile);

	profile.standard = "PAL";
	profile.rez = QSize(352, 480);
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// MPEG-2
	profile.codec = "mpeg2video";

	// Low (CVD)
	profile.level = Video::Profile::Low;
	profile.standard = "NTSC";
	profile.rez = QSize(352, 480);
	profile.bitrate = 2520.0;
	profileVideos.insertMulti(profile.codec, profile);

	profile.standard = "PAL";
	profile.rez = QSize(352, 576);
	profileVideos.insertMulti(profile.codec, profile);
	 
	// Medium (SVCD)
	profile.level = Video::Profile::Medium;
	profile.standard = "NTSC";
	profile.rez = QSize(480, 480);
	profile.bitrate = 2520.0;
	profileVideos.insertMulti(profile.codec, profile);

	profile.standard = "PAL";
	profile.rez = QSize(480, 576);
	profileVideos.insertMulti(profile.codec, profile);

	// High (DVD)
	profile.level = Video::Profile::High;
	profile.standard = "NTSC";
	profile.rez = QSize(720, 480);
	profile.bitrate = 4900.0;
	profileVideos.insertMulti(profile.codec, profile);

	profile.standard = "PAL";
	profile.rez = QSize(720, 576);
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// XVID
	profile.codec = "xvid";

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(480, 272);
	profile.bitrate = 768.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "";
	profile.rez = QSize(624, 352);
	profile.bitrate = 896.0;
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "";
	profile.rez = QSize(624, 352);
	profile.bitrate = 1024.0;
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// MPEG-4
	profile.codec = "mpeg4";

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(480, 272);
	profile.bitrate = 768.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "";
	profile.rez = QSize(624, 352);
	profile.bitrate = 896.0;
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "";
	profile.rez = QSize(624, 352);
	profile.bitrate = 1024.0;
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// H.264
	profile.codec = "x264";

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(480, 272);
	profile.bitrate = 768.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "NTSC";
	profile.rez = QSize(528, 320);
	profile.bitrate = 896.0;
	profileVideos.insertMulti(profile.codec, profile);

	profile.standard = "PAL";
	profile.rez = QSize(528, 384);
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "NTSC";
	profile.rez = QSize(528, 320);
	profile.bitrate = 1024.0;
	profileVideos.insertMulti(profile.codec, profile);

	profile.standard = "PAL";
	profile.rez = QSize(528, 384);
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// H.264 Low Rates
	profile.codec = "x264_lr";

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(128, 96);
	profile.bitrate = 64.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "";
	profile.rez = QSize(176, 144);
	profile.bitrate = 128.0;
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "NTSC";
	profile.rez = QSize(352, 240);
	profile.bitrate = 256.0;
	profileVideos.insertMulti(profile.codec, profile);

	profile.standard = "PAL";
	profile.rez = QSize(352, 288);
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// H.264 HighDef
	profile.codec = "x264_hd";

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(960, 544);
	profile.bitrate = 2000.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "";
	profile.rez = QSize(1280, 720);
	profile.bitrate = 4000.0;
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "";
	profile.rez = QSize(1920, 1088);
	profile.bitrate = 6000.0;
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// H.264 PSP
	profile.codec = "x264_psp";

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(384, 240);
	profile.bitrate = 800.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "";
	profile.rez = QSize(480, 272);
	profile.bitrate = 1100.0;
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "";
	profile.rez = QSize(480, 272);
	profile.bitrate = 1800.0;
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// H.264 DivX Plus HD
	profile.codec = "x264_divx";

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(960, 544);
	profile.bitrate = 2000.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "";
	profile.rez = QSize(1280, 720);
	profile.bitrate = 4000.0;
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "";
	profile.rez = QSize(1920, 1088);
	profile.bitrate = 6000.0;
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// Theora
	profile.codec = "theora";

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(528, 384);
	profile.bitrate = 768.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "";
	profile.rez = QSize(624, 352);
	profile.bitrate = 1024.0;
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "";
	profile.rez = QSize(1280, 720);
	profile.bitrate = 1536.0;
	profileVideos.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// VP8
	profile.codec = "vp8";

	// Low
	profile.level = Video::Profile::Low;
	profile.standard = "";
	profile.rez = QSize(480, 272);
	profile.bitrate = 768.0;
	profileVideos.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.standard = "";
	profile.rez = QSize(624, 352);
	profile.bitrate = 896.0;
	profileVideos.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.standard = "";
	profile.rez = QSize(624, 352);
	profile.bitrate = 1024.0;
	profileVideos.insertMulti(profile.codec, profile);
}

void Configurator::setAudioProfiles()
{
	encoder_audio_profile_t profile;

	////////////////////////////////////////////////////////////
	// AMR-NB
	profile.codec = "amrnb";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 8000;  // AMR-NB only supports 8kHz mono
	profile.bitrate = 4.750;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 8000;
	profile.bitrate = 7.950;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 8000;
	profile.bitrate = 12.200;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// AAC Low Rates
	profile.codec = "aac_lr";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 16000;
	profile.bitrate = 32.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 32000;
	profile.bitrate = 48.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 44100;
	profile.bitrate = 64.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// AAC
	profile.codec = "aac";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 44100;
	profile.bitrate = 96.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 48000;
	profile.bitrate = 128.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 48000;
	profile.bitrate = 160.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// AAC for HD video
	profile.codec = "aac_hq";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 44100;
	profile.bitrate = 160.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 48000;
	profile.bitrate = 192.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 48000;
	profile.bitrate = 256.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// AAC for Flash Video (11025, 22050 and 44100 only)
	profile.codec = "aac_flv";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 22050;
	profile.bitrate = 48.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 44100;
	profile.bitrate = 64.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 44100;
	profile.bitrate = 96.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// MP3
	profile.codec = "mp3";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 44100;
	profile.bitrate = 112.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 44100;
	profile.bitrate = 160.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 48000;
	profile.bitrate = 192.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// MP3 Low Rates
	profile.codec = "mp3_lr";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 16000;
	profile.bitrate = 32.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 24000;
	profile.bitrate = 48.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 32000;
	profile.bitrate = 64.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// MP3 for Flash Video (11025, 22050 and 44100 only)
	profile.codec = "mp3_flv";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 44100;
	profile.bitrate = 112.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 44100;
	profile.bitrate = 160.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 44100;
	profile.bitrate = 192.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// MP3 Low Rates for Flash Video (11025, 22050 and 44100 only)
	profile.codec = "mp3_flv_lr";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 11025;
	profile.bitrate = 24.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 22050;
	profile.bitrate = 48.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 22050;
	profile.bitrate = 64.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// MP2
	profile.codec = "mp2";

	// Low (CVD)
	profile.level = Video::Profile::Low;
	profile.sampling = 44100;
	profile.bitrate = 224.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium (SVCD)
	profile.level = Video::Profile::Medium;
	profile.sampling = 44100;
	profile.bitrate = 224.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High (DVD)
	profile.level = Video::Profile::High;
	profile.sampling = 48000;
	profile.bitrate = 384.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// MP2-VCD
	profile.codec = "mp2_vcd";

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 44100;
	profile.bitrate = 224.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 44100;
	profile.bitrate = 224.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// AC3
	profile.codec = "ac3";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 48000;
	profile.bitrate = 192.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 48000;
	profile.bitrate = 256.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 48000;
	profile.bitrate = 384.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Copy
	profile.level = Video::Profile::Copy;
	profile.sampling = -1;	// source copy
	profile.bitrate = 0.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// AC3 copy
	profile.codec = "ac3_copy";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = -1;	// source copy
	profile.bitrate = 0.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profileAudios.insertMulti(profile.codec, profile);

	// Copy
	profile.level = Video::Profile::High;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// PCM
	profile.codec = "pcm";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 48000;
	profile.bitrate = 1536.0;  // 2 channels, 16 bits
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 96000;
	profile.bitrate = 3072.0;  // 2 channels, 16 bits
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 96000;
	profile.bitrate = 6144.0;  // 2 channels, 32 bits
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// Vorbis
	profile.codec = "vorbis";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 44100;
	profile.bitrate = 128.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 44100;
	profile.bitrate = 160.0;
	profileAudios.insertMulti(profile.codec, profile);

	// High
	profile.level = Video::Profile::High;
	profile.sampling = 44100;
	profile.bitrate = 192.0;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// Apple Lossless Audio Codec
	profile.codec = "alac";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 44100;
	profile.bitrate = 0.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 44100;
	profileAudios.insertMulti(profile.codec, profile);

	// Copy
	profile.level = Video::Profile::High;
	profile.sampling = 48000;
	profileAudios.insertMulti(profile.codec, profile);

	////////////////////////////////////////////////////////////
	// Free Lossless Audio Codec
	profile.codec = "flac";

	// Low
	profile.level = Video::Profile::Low;
	profile.sampling = 44100;
	profile.bitrate = 0.0;
	profileAudios.insertMulti(profile.codec, profile);

	// Medium
	profile.level = Video::Profile::Medium;
	profile.sampling = 44100;
	profileAudios.insertMulti(profile.codec, profile);

	// Copy
	profile.level = Video::Profile::High;
	profile.sampling = 48000;
	profileAudios.insertMulti(profile.codec, profile);
}
