gt: 							if (media.getWidth() > 1280) {
context: /*
   * PS3 Media Server, for streaming any medias to your PS3.
   * Copyright (C) 2008  A.Brochard
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; version 2
   * of the License only.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   */
  package net.pms.encoders;
  
  import bsh.EvalError;
  import bsh.Interpreter;
  import com.jgoodies.forms.builder.PanelBuilder;
  import com.jgoodies.forms.factories.Borders;
  import com.jgoodies.forms.layout.CellConstraints;
  import com.jgoodies.forms.layout.FormLayout;
  import com.sun.jna.Platform;
  import java.awt.*;
  import java.awt.event.*;
  import java.io.File;
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.util.*;
  import java.util.List;
  import javax.swing.*;
  import net.pms.Messages;
  import net.pms.PMS;
  import net.pms.configuration.DeviceConfiguration;
  import net.pms.configuration.FormatConfiguration;
  import net.pms.configuration.PmsConfiguration;
  import net.pms.configuration.RendererConfiguration;
  import net.pms.dlna.*;
  import net.pms.formats.Format;
  import static net.pms.formats.v2.AudioUtils.getLPCMChannelMappingForMencoder;
  import net.pms.formats.v2.SubtitleType;
  import net.pms.io.*;
  import net.pms.network.HTTPResource;
  import net.pms.newgui.GuiUtil;
  import net.pms.newgui.components.CustomJButton;
  import net.pms.util.*;
  import static net.pms.util.StringUtil.quoteArg;
  import org.apache.commons.configuration.event.ConfigurationEvent;
  import org.apache.commons.configuration.event.ConfigurationListener;
  import static org.apache.commons.lang.BooleanUtils.isTrue;
  import static org.apache.commons.lang3.StringUtils.*;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  public class MEncoderVideo extends Player {
  	private static final Logger LOGGER = LoggerFactory.getLogger(MEncoderVideo.class);
  	private static final String COL_SPEC = "left:pref, 3dlu, p:grow, 3dlu, right:p:grow, 3dlu, p:grow, 3dlu, right:p:grow,3dlu, p:grow, 3dlu, right:p:grow,3dlu, pref:grow";
  	private static final String ROW_SPEC = "p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 9dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p";
  	private static final String REMOVE_OPTION = "---REMOVE-ME---"; // use an out-of-band option that can't be confused with a real option
  
  	private JTextField mencoder_noass_scale;
  	private JTextField mencoder_noass_subpos;
  	private JTextField mencoder_noass_blur;
  	private JTextField mencoder_noass_outline;
  	private JTextField mencoder_custom_options;
  	private JTextField subq;
  	private JCheckBox forcefps;
  	private JCheckBox yadif;
  	private JCheckBox scaler;
  	private JTextField scaleX;
  	private JTextField scaleY;
  	private JCheckBox fc;
  	private JCheckBox ass;
  	private JCheckBox skipLoopFilter;
  	private JCheckBox mencodermt;
  	private JCheckBox videoremux;
  	private JCheckBox normalizeaudio;
  	private JCheckBox noskip;
  	private JCheckBox intelligentsync;
  	private JTextField ocw;
  	private JTextField och;
  
  	private static final String[] INVALID_CUSTOM_OPTIONS = {
  		"-of",
  		"-oac",
  		"-ovc",
  		"-mpegopts"
  	};
  
  	private static final String INVALID_CUSTOM_OPTIONS_LIST = Arrays.toString(INVALID_CUSTOM_OPTIONS);
  
  	public static final int MENCODER_MAX_THREADS = 8;
  	public static final String ID = "mencoder";
  
  	// TODO (breaking change): most (probably all) of these
  	// protected fields should be private. And at least two
  	// shouldn't be fields
  
  	@Deprecated
  	protected boolean dvd;
  
  	@Deprecated
  	protected String overriddenMainArgs[];
  
  	protected boolean dtsRemux;
  	protected boolean encodedAudioPassthrough;
  	protected boolean pcm;
  	protected boolean ovccopy;
  	protected boolean ac3Remux;
  	protected boolean isTranscodeToMPEGTS;
  	protected boolean isTranscodeToH264;
  	protected boolean isTranscodeToAAC;
  	protected boolean wmv;
  
  	public static final String DEFAULT_CODEC_CONF_SCRIPT =
  		Messages.getString("MEncoderVideo.68") +
  		Messages.getString("MEncoderVideo.70") +
  		Messages.getString("MEncoderVideo.71") +
  		Messages.getString("MEncoderVideo.72") +
  		Messages.getString("MEncoderVideo.75") +
  		Messages.getString("MEncoderVideo.76") +
  		Messages.getString("MEncoderVideo.77") +
  		Messages.getString("MEncoderVideo.78") +
  		Messages.getString("MEncoderVideo.135") +
  		"\n" +
  		"container == iso :: -nosync\n" +
  		"(container == avi || container == matroska) && vcodec == mpeg4 && acodec == mp3 :: -mc 0.1\n" +
  		"container == flv :: -mc 0.1\n" +
  		"container == mov :: -mc 0.1\n" +
  		"container == rm  :: -mc 0.1\n" +
  		"container == mp4 && vcodec == h264 :: -mc 0.1\n" +
  		"\n" +
  		Messages.getString("MEncoderVideo.87") +
  		Messages.getString("MEncoderVideo.89") +
  		Messages.getString("MEncoderVideo.91");
  
  	@Deprecated
  	public JCheckBox getCheckBox() {
  		return skipLoopFilter;
  	}
  
  	public JCheckBox getNoskip() {
  		return noskip;
  	}
  
  	@Deprecated
  	public MEncoderVideo(PmsConfiguration configuration) {
  		this();
  	}
  
  	public MEncoderVideo() {
  	}
  
  	@Override
  	public JComponent config() {
  		// Apply the orientation for the locale
  		Locale locale = new Locale(configuration.getLanguage());
  		ComponentOrientation orientation = ComponentOrientation.getOrientation(locale);
  		String colSpec = FormLayoutUtil.getColSpec(COL_SPEC, orientation);
  
  		FormLayout layout = new FormLayout(colSpec, ROW_SPEC);
  		PanelBuilder builder = new PanelBuilder(layout);
  		builder.border(Borders.EMPTY);
  		builder.opaque(false);
  
  		CellConstraints cc = new CellConstraints();
  
  		JComponent cmp = builder.addSeparator(Messages.getString("NetworkTab.5"), FormLayoutUtil.flip(cc.xyw(1, 1, 15), colSpec, orientation));
  		cmp = (JComponent) cmp.getComponent(0);
  		cmp.setFont(cmp.getFont().deriveFont(Font.BOLD));
  
  		mencodermt = new JCheckBox(Messages.getString("MEncoderVideo.35"), configuration.getMencoderMT());
  		mencodermt.setContentAreaFilled(false);
  		mencodermt.addActionListener(new ActionListener() {
  			@Override
  			public void actionPerformed(ActionEvent e) {
  				configuration.setMencoderMT(mencodermt.isSelected());
  			}
  		});
  		mencodermt.setEnabled(Platform.isWindows() || Platform.isMac());
  		builder.add(GuiUtil.getPreferredSizeComponent(mencodermt), FormLayoutUtil.flip(cc.xy(1, 3), colSpec, orientation));
  
  		skipLoopFilter = new JCheckBox(Messages.getString("MEncoderVideo.0"), configuration.getSkipLoopFilterEnabled());
  		skipLoopFilter.setContentAreaFilled(false);
  		skipLoopFilter.setToolTipText(Messages.getString("MEncoderVideo.136"));
  		skipLoopFilter.addItemListener(new ItemListener() {
  			@Override
  			public void itemStateChanged(ItemEvent e) {
  				configuration.setSkipLoopFilterEnabled((e.getStateChange() == ItemEvent.SELECTED));
  			}
  		});
  		builder.add(GuiUtil.getPreferredSizeComponent(skipLoopFilter), FormLayoutUtil.flip(cc.xyw(3, 3, 12), colSpec, orientation));
  
  		noskip = new JCheckBox(Messages.getString("MEncoderVideo.2"), configuration.isMencoderNoOutOfSync());
  		noskip.setContentAreaFilled(false);
  		noskip.addItemListener(new ItemListener() {
  			@Override
  			public void itemStateChanged(ItemEvent e) {
  				configuration.setMencoderNoOutOfSync((e.getStateChange() == ItemEvent.SELECTED));
  			}
  		});
  		builder.add(GuiUtil.getPreferredSizeComponent(noskip), FormLayoutUtil.flip(cc.xy(1, 5), colSpec, orientation));
  
  		CustomJButton button = new CustomJButton(Messages.getString("MEncoderVideo.29"));
  		button.addActionListener(new ActionListener() {
  			@Override
  			public void actionPerformed(ActionEvent e) {
  				JPanel codecPanel = new JPanel(new BorderLayout());
  				final JTextArea textArea = new JTextArea();
  				textArea.setText(configuration.getMencoderCodecSpecificConfig());
  				textArea.setFont(new Font("Courier", Font.PLAIN, 12));
  				JScrollPane scrollPane = new JScrollPane(textArea);
  				scrollPane.setPreferredSize(new Dimension(900, 100));
  
  				final JTextArea textAreaDefault = new JTextArea();
  				textAreaDefault.setText(DEFAULT_CODEC_CONF_SCRIPT);
  				textAreaDefault.setBackground(Color.WHITE);
  				textAreaDefault.setFont(new Font("Courier", Font.PLAIN, 12));
  				textAreaDefault.setEditable(false);
  				textAreaDefault.setEnabled(configuration.isMencoderIntelligentSync());
  				JScrollPane scrollPaneDefault = new JScrollPane(textAreaDefault);
  				scrollPaneDefault.setPreferredSize(new Dimension(900, 450));
  
  				JPanel customPanel = new JPanel(new BorderLayout());
  				intelligentsync = new JCheckBox(Messages.getString("MEncoderVideo.3"), configuration.isMencoderIntelligentSync());
  				intelligentsync.setContentAreaFilled(false);
  				intelligentsync.addItemListener(new ItemListener() {
  					@Override
  					public void itemStateChanged(ItemEvent e) {
  						configuration.setMencoderIntelligentSync((e.getStateChange() == ItemEvent.SELECTED));
  						textAreaDefault.setEnabled(configuration.isMencoderIntelligentSync());
  
  					}
  				});
  
  				JLabel label = new JLabel(Messages.getString("MEncoderVideo.33"));
  				customPanel.add(label, BorderLayout.NORTH);
  				customPanel.add(scrollPane, BorderLayout.SOUTH);
  
  				codecPanel.add(intelligentsync, BorderLayout.NORTH);
  				codecPanel.add(scrollPaneDefault, BorderLayout.CENTER);
  				codecPanel.add(customPanel, BorderLayout.SOUTH);
  
  				while (JOptionPane.showOptionDialog(SwingUtilities.getWindowAncestor((Component) PMS.get().getFrame()),
  					codecPanel, Messages.getString("MEncoderVideo.34"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, null, null) == JOptionPane.OK_OPTION) {
  					String newCodecparam = textArea.getText();
  					DLNAMediaInfo fakemedia = new DLNAMediaInfo();
  					DLNAMediaAudio audio = new DLNAMediaAudio();
  					audio.setCodecA("ac3");
  					fakemedia.setCodecV("mpeg4");
  					fakemedia.setContainer("matroska");
  					fakemedia.setDuration(45d*60);
  					audio.getAudioProperties().setNumberOfChannels(2);
  					fakemedia.setWidth(1280);
  					fakemedia.setHeight(720);
  					audio.setSampleFrequency("48000");
  					fakemedia.setFrameRate("23.976");
  					fakemedia.getAudioTracksList().add(audio);
  					String result[] = getSpecificCodecOptions(newCodecparam, fakemedia, new OutputParams(configuration), "dummy.mpg", "dummy.srt", false, true);
  
  					if (result.length > 0 && result[0].startsWith("@@")) {
  						String errorMessage = result[0].substring(2);
  						JOptionPane.showMessageDialog(
  							SwingUtilities.getWindowAncestor((Component) PMS.get().getFrame()),
  							errorMessage,
  							Messages.getString("Dialog.Error"),
  							JOptionPane.ERROR_MESSAGE
  						);
  					} else {
  						configuration.setMencoderCodecSpecificConfig(newCodecparam);
  						break;
  					}
  				}
  			}
  		});
  		builder.add(button, FormLayoutUtil.flip(cc.xy(1, 11), colSpec, orientation));
  
  		forcefps = new JCheckBox(Messages.getString("MEncoderVideo.4"), configuration.isMencoderForceFps());
  		forcefps.setContentAreaFilled(false);
  		forcefps.addItemListener(new ItemListener() {
  			@Override
  			public void itemStateChanged(ItemEvent e) {
  				configuration.setMencoderForceFps(e.getStateChange() == ItemEvent.SELECTED);
  			}
  		});
  
  		builder.add(GuiUtil.getPreferredSizeComponent(forcefps), FormLayoutUtil.flip(cc.xyw(1, 7, 2), colSpec, orientation));
  
  		yadif = new JCheckBox(Messages.getString("MEncoderVideo.26"), configuration.isMencoderYadif());
  		yadif.setContentAreaFilled(false);
  		yadif.addItemListener(new ItemListener() {
  			@Override
  			public void itemStateChanged(ItemEvent e) {
  				configuration.setMencoderYadif(e.getStateChange() == ItemEvent.SELECTED);
  			}
  		});
  		builder.add(GuiUtil.getPreferredSizeComponent(yadif), FormLayoutUtil.flip(cc.xyw(3, 7, 7), colSpec, orientation));
  
  		scaler = new JCheckBox(Messages.getString("MEncoderVideo.27"));
  		scaler.setContentAreaFilled(false);
  		scaler.addItemListener(new ItemListener() {
  			@Override
  			public void itemStateChanged(ItemEvent e) {
  				configuration.setMencoderScaler(e.getStateChange() == ItemEvent.SELECTED);
  				scaleX.setEnabled(configuration.isMencoderScaler());
  				scaleY.setEnabled(configuration.isMencoderScaler());
  			}
  		});
  		builder.add(GuiUtil.getPreferredSizeComponent(scaler), FormLayoutUtil.flip(cc.xyw(3, 5, 7), colSpec, orientation));
  
  		builder.addLabel(Messages.getString("MEncoderVideo.28"), FormLayoutUtil.flip(cc.xy(9, 5, CellConstraints.RIGHT, CellConstraints.CENTER), colSpec, orientation));
  		scaleX = new JTextField("" + configuration.getMencoderScaleX());
  		scaleX.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				try {
  					configuration.setMencoderScaleX(Integer.parseInt(scaleX.getText()));
  				} catch (NumberFormatException nfe) {
  					LOGGER.debug("Could not parse scaleX from \"" + scaleX.getText() + "\"");
  				}
  			}
  		});
  		builder.add(scaleX, FormLayoutUtil.flip(cc.xy(11, 5), colSpec, orientation));
  
  		builder.addLabel(Messages.getString("MEncoderVideo.30"), FormLayoutUtil.flip(cc.xy(13, 5, CellConstraints.RIGHT, CellConstraints.CENTER), colSpec, orientation));
  		scaleY = new JTextField("" + configuration.getMencoderScaleY());
  		scaleY.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				try {
  					configuration.setMencoderScaleY(Integer.parseInt(scaleY.getText()));
  				} catch (NumberFormatException nfe) {
  					LOGGER.debug("Could not parse scaleY from \"" + scaleY.getText() + "\"");
  				}
  			}
  		});
  		builder.add(scaleY, FormLayoutUtil.flip(cc.xy(15, 5), colSpec, orientation));
  
  		if (configuration.isMencoderScaler()) {
  			scaler.setSelected(true);
  		} else {
  			scaleX.setEnabled(false);
  			scaleY.setEnabled(false);
  		}
  
  		videoremux = new JCheckBox(Messages.getString("MEncoderVideo.38"), configuration.isMencoderMuxWhenCompatible());
  		videoremux.setContentAreaFilled(false);
  		videoremux.addItemListener(new ItemListener() {
  			@Override
  			public void itemStateChanged(ItemEvent e) {
  				configuration.setMencoderMuxWhenCompatible((e.getStateChange() == ItemEvent.SELECTED));
  			}
  		});
  		builder.add(GuiUtil.getPreferredSizeComponent(videoremux), FormLayoutUtil.flip(cc.xyw(1, 9, 13), colSpec, orientation));
  
  		normalizeaudio = new JCheckBox(Messages.getString("MEncoderVideo.134"), configuration.isMEncoderNormalizeVolume());
  		normalizeaudio.setContentAreaFilled(false);
  		normalizeaudio.addItemListener(new ItemListener() {
  			@Override
  			public void itemStateChanged(ItemEvent e) {
  				configuration.setMEncoderNormalizeVolume((e.getStateChange() == ItemEvent.SELECTED));
  			}
  		});
  		// Uncomment this if volume normalizing in MEncoder is ever fixed.
  		// builder.add(normalizeaudio, FormLayoutUtil.flip(cc.xyw(1, 13, 13), colSpec, orientation));
  
  		builder.addLabel(Messages.getString("MEncoderVideo.6"), FormLayoutUtil.flip(cc.xy(1, 15), colSpec, orientation));
  		mencoder_custom_options = new JTextField(configuration.getMencoderCustomOptions());
  		mencoder_custom_options.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				configuration.setMencoderCustomOptions(mencoder_custom_options.getText());
  			}
  		});
  		builder.add(mencoder_custom_options, FormLayoutUtil.flip(cc.xyw(3, 15, 13), colSpec, orientation));
  
  		builder.addLabel(Messages.getString("MEncoderVideo.93"), FormLayoutUtil.flip(cc.xy(1, 17), colSpec, orientation));
  
  		builder.addLabel(Messages.getString("MEncoderVideo.28") + " (%)", FormLayoutUtil.flip(cc.xy(1, 17, CellConstraints.RIGHT, CellConstraints.CENTER), colSpec, orientation));
  		ocw = new JTextField(configuration.getMencoderOverscanCompensationWidth());
  		ocw.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				configuration.setMencoderOverscanCompensationWidth(ocw.getText());
  			}
  		});
  		builder.add(ocw, FormLayoutUtil.flip(cc.xy(3, 17), colSpec, orientation));
  
  		builder.addLabel(Messages.getString("MEncoderVideo.30") + " (%)", FormLayoutUtil.flip(cc.xy(5, 17), colSpec, orientation));
  		och = new JTextField(configuration.getMencoderOverscanCompensationHeight());
  		och.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				configuration.setMencoderOverscanCompensationHeight(och.getText());
  			}
  		});
  		builder.add(och, FormLayoutUtil.flip(cc.xy(7, 17), colSpec, orientation));
  
  		cmp = builder.addSeparator(Messages.getString("MEncoderVideo.8"), FormLayoutUtil.flip(cc.xyw(1, 19, 15), colSpec, orientation));
  		cmp = (JComponent) cmp.getComponent(0);
  		cmp.setFont(cmp.getFont().deriveFont(Font.BOLD));
  
  		builder.addLabel(Messages.getString("MEncoderVideo.16"), FormLayoutUtil.flip(cc.xy(1, 27), colSpec, orientation));
  		builder.addLabel(Messages.getString("MEncoderVideo.133"), FormLayoutUtil.flip(cc.xy(1, 27, CellConstraints.RIGHT, CellConstraints.CENTER), colSpec, orientation));
  
  		mencoder_noass_scale = new JTextField(configuration.getMencoderNoAssScale());
  		mencoder_noass_scale.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				configuration.setMencoderNoAssScale(mencoder_noass_scale.getText());
  			}
  		});
  
  		builder.addLabel(Messages.getString("MEncoderVideo.17"), FormLayoutUtil.flip(cc.xy(5, 27), colSpec, orientation));
  
  		mencoder_noass_outline = new JTextField(configuration.getMencoderNoAssOutline());
  		mencoder_noass_outline.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				configuration.setMencoderNoAssOutline(mencoder_noass_outline.getText());
  			}
  		});
  
  		builder.addLabel(Messages.getString("MEncoderVideo.18"), FormLayoutUtil.flip(cc.xy(9, 27), colSpec, orientation));
  
  		mencoder_noass_blur = new JTextField(configuration.getMencoderNoAssBlur());
  		mencoder_noass_blur.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				configuration.setMencoderNoAssBlur(mencoder_noass_blur.getText());
  			}
  		});
  
  		builder.addLabel(Messages.getString("MEncoderVideo.19"), FormLayoutUtil.flip(cc.xy(13, 27), colSpec, orientation));
  
  		mencoder_noass_subpos = new JTextField(configuration.getMencoderNoAssSubPos());
  		mencoder_noass_subpos.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				configuration.setMencoderNoAssSubPos(mencoder_noass_subpos.getText());
  			}
  		});
  
  		builder.add(mencoder_noass_scale, FormLayoutUtil.flip(cc.xy(3, 27), colSpec, orientation));
  		builder.add(mencoder_noass_outline, FormLayoutUtil.flip(cc.xy(7, 27), colSpec, orientation));
  		builder.add(mencoder_noass_blur, FormLayoutUtil.flip(cc.xy(11, 27), colSpec, orientation));
  		builder.add(mencoder_noass_subpos, FormLayoutUtil.flip(cc.xy(15, 27), colSpec, orientation));
  
  		ass = new JCheckBox(Messages.getString("MEncoderVideo.20"), configuration.isMencoderAss());
  		ass.setContentAreaFilled(false);
  		ass.addItemListener(new ItemListener() {
  			@Override
  			public void itemStateChanged(ItemEvent e) {
  				if (e != null) {
  					configuration.setMencoderAss(e.getStateChange() == ItemEvent.SELECTED);
  				}
  			}
  		});
  		builder.add(GuiUtil.getPreferredSizeComponent(ass), FormLayoutUtil.flip(cc.xy(1, 23), colSpec, orientation));
  		ass.getItemListeners()[0].itemStateChanged(null);
  
  		fc = new JCheckBox(Messages.getString("MEncoderVideo.21"), configuration.isMencoderFontConfig());
  		fc.setContentAreaFilled(false);
  		fc.addItemListener(new ItemListener() {
  			@Override
  			public void itemStateChanged(ItemEvent e) {
  				configuration.setMencoderFontConfig(e.getStateChange() == ItemEvent.SELECTED);
  			}
  		});
  		builder.add(GuiUtil.getPreferredSizeComponent(fc), FormLayoutUtil.flip(cc.xyw(3, 23, 5), colSpec, orientation));
  
  		builder.addLabel(Messages.getString("MEncoderVideo.92"), FormLayoutUtil.flip(cc.xy(1, 29), colSpec, orientation));
  		subq = new JTextField(configuration.getMencoderVobsubSubtitleQuality());
  		subq.addKeyListener(new KeyAdapter() {
  			@Override
  			public void keyReleased(KeyEvent e) {
  				configuration.setMencoderVobsubSubtitleQuality(subq.getText());
  			}
  		});
  		builder.add(subq, FormLayoutUtil.flip(cc.xyw(3, 29, 1), colSpec, orientation));
  
  		configuration.addConfigurationListener(new ConfigurationListener() {
  			@Override
  			public void configurationChanged(ConfigurationEvent event) {
  				if (event.getPropertyName() == null) {
  					return;
  				}
  				if ((!event.isBeforeUpdate()) && event.getPropertyName().equals(PmsConfiguration.KEY_DISABLE_SUBTITLES)) {
  					boolean enabled = !configuration.isDisableSubtitles();
  					ass.setEnabled(enabled);
  					fc.setEnabled(enabled);
  					mencoder_noass_scale.setEnabled(enabled);
  					mencoder_noass_outline.setEnabled(enabled);
  					mencoder_noass_blur.setEnabled(enabled);
  					mencoder_noass_subpos.setEnabled(enabled);
  					ocw.setEnabled(enabled);
  					och.setEnabled(enabled);
  					subq.setEnabled(enabled);
  
  					if (enabled) {
  						ass.getItemListeners()[0].itemStateChanged(null);
  					}
  				}
  			}
  		});
  
  		JPanel panel = builder.getPanel();
  
  		// Apply the orientation to the panel and all components in it
  		panel.applyComponentOrientation(orientation);
  
  		return panel;
  	}
  
  	@Override
  	public int purpose() {
  		return VIDEO_SIMPLEFILE_PLAYER;
  	}
  
  	@Override
  	public String id() {
  		return ID;
  	}
  
  	@Override
  	public boolean avisynth() {
  		return false;
  	}
  
  	@Override
  	public boolean isTimeSeekable() {
  		return true;
  	}
  
  	protected String[] getDefaultArgs() {
  		List<String> defaultArgsList = new ArrayList<>();
  
  		defaultArgsList.add("-msglevel");
  		defaultArgsList.add("statusline=2");
  
  		defaultArgsList.add("-oac");
  		if (ac3Remux || dtsRemux) {
  			defaultArgsList.add("copy");
  		} else if (pcm) {
  			defaultArgsList.add("pcm");
  		} else if (isTranscodeToAAC) {
  			defaultArgsList.add("faac");
  			defaultArgsList.add("-faacopts");
  			defaultArgsList.add("br=320:mpeg=4:object=2");
  		} else {
  			defaultArgsList.add("lavc");
  		}
  
  		defaultArgsList.add("-of");
  		if (wmv || isTranscodeToMPEGTS) {
  			defaultArgsList.add("lavf");
  		} else if (pcm && avisynth()) {
  			defaultArgsList.add("avi");
  		} else if (pcm || dtsRemux || encodedAudioPassthrough) {
  			defaultArgsList.add("rawvideo");
  		} else {
  			defaultArgsList.add("mpeg");
  		}
  
  		if (wmv) {
  			defaultArgsList.add("-lavfopts");
  			defaultArgsList.add("format=asf");
  		} else if (isTranscodeToMPEGTS) {
  			defaultArgsList.add("-lavfopts");
  			defaultArgsList.add("format=mpegts");
  		}
  
  		defaultArgsList.add("-mpegopts");
  		defaultArgsList.add("format=mpeg2:muxrate=500000:vbuf_size=1194:abuf_size=64");
  
  		defaultArgsList.add("-ovc");
  		defaultArgsList.add(ovccopy ? "copy" : "lavc");
  
  		String[] defaultArgsArray = new String[defaultArgsList.size()];
  		defaultArgsList.toArray(defaultArgsArray);
  
  		return defaultArgsArray;
  	}
  
  	private String[] sanitizeArgs(String[] args) {
  		List<String> sanitized = new ArrayList<>();
  		int i = 0;
  
  		while (i < args.length) {
  			String name = args[i];
  			String value = null;
  
  			for (String option : INVALID_CUSTOM_OPTIONS) {
  				if (option.equals(name)) {
  					if ((i + 1) < args.length) {
  						value = " " + args[i + 1];
  						++i;
  					} else {
  						value = "";
  					}
  
  					LOGGER.warn(
  						"Ignoring custom MEncoder option: {}{}; the following options cannot be changed: " + INVALID_CUSTOM_OPTIONS_LIST,
  						name,
  						value
  					);
  
  					break;
  				}
  			}
  
  			if (value == null) {
  				sanitized.add(args[i]);
  			}
  
  			++i;
  		}
  
  		return sanitized.toArray(new String[sanitized.size()]);
  	}
  
  	@Override
  	public String[] args() {
  		String args[];
  		String defaultArgs[] = getDefaultArgs();
  
  		if (overriddenMainArgs != null) {
  			// add the sanitized custom MEncoder options.
  			// not cached because they may be changed on the fly in the GUI
  			// TODO if/when we upgrade to org.apache.commons.lang3:
  			// args = ArrayUtils.addAll(defaultArgs, sanitizeArgs(overriddenMainArgs))
  			String[] sanitizedCustomArgs = sanitizeArgs(overriddenMainArgs);
  			args = new String[defaultArgs.length + sanitizedCustomArgs.length];
  			System.arraycopy(defaultArgs, 0, args, 0, defaultArgs.length);
  			System.arraycopy(sanitizedCustomArgs, 0, args, defaultArgs.length, sanitizedCustomArgs.length);
  		} else {
  			args = defaultArgs;
  		}
  
  		return args;
  	}
  
  	@Override
  	public String executable() {
  		return configuration.getMencoderPath();
  	}
  
  	private int[] getVideoBitrateConfig(String bitrate) {
  		int bitrates[] = new int[2];
  
  		if (bitrate.contains("(") && bitrate.contains(")")) {
  			try {
  				bitrates[1] = Integer.parseInt(bitrate.substring(bitrate.indexOf('(') + 1, bitrate.indexOf(')')));
  			} catch (NumberFormatException e) {
  				bitrates[1] = 0;
  			}
  		}
  
  		if (bitrate.contains("(")) {
  			bitrate = bitrate.substring(0, bitrate.indexOf('(')).trim();
  		}
  
  		if (isBlank(bitrate)) {
  			bitrate = "0";
  		}
  
  		try {
  			bitrates[0] = (int) Double.parseDouble(bitrate);
  		} catch (NumberFormatException e) {
  			bitrates[0] = 0;
  		}
  
  		return bitrates;
  	}
  
  	/**
  	 * Note: This is not exact. The bitrate can go above this but it is generally pretty good.
  	 *
  	 * @return The maximum bitrate the video should be along with the buffer size using MEncoder vars
  	 */
  	private String addMaximumBitrateConstraints(String encodeSettings, DLNAMediaInfo media, String quality, RendererConfiguration mediaRenderer, String audioType) {
  		PmsConfiguration configuration = PMS.getConfiguration(mediaRenderer);
  		int defaultMaxBitrates[] = getVideoBitrateConfig(configuration.getMaximumBitrate());
  		int rendererMaxBitrates[] = new int[2];
  
  		if (isNotEmpty(mediaRenderer.getMaxVideoBitrate())) {
  			rendererMaxBitrates = getVideoBitrateConfig(mediaRenderer.getMaxVideoBitrate());
  		}
  
  		// Give priority to the renderer's maximum bitrate setting over the user's setting
  		if (rendererMaxBitrates[0] > 0 && rendererMaxBitrates[0] < defaultMaxBitrates[0]) {
  			defaultMaxBitrates = rendererMaxBitrates;
  			LOGGER.trace("Using the video bitrate limit from the renderer config (" + rendererMaxBitrates[0] + ") which is lower than the one from the program settings (" + defaultMaxBitrates[0] + ")");
  		} else {
  			LOGGER.trace("Using the video bitrate limit from the program settings (" + defaultMaxBitrates[0] + ")");
  		}
  
  		if (mediaRenderer.getCBRVideoBitrate() == 0 && !quality.contains("vrc_buf_size") && !quality.contains("vrc_maxrate") && !quality.contains("vbitrate")) {
  			// Convert value from Mb to Kb
  			defaultMaxBitrates[0] = 1000 * defaultMaxBitrates[0];
  
  			// Halve it since it seems to send up to 1 second of video in advance
  			defaultMaxBitrates[0] /= 2;
  			LOGGER.trace("Halving the video bitrate limit to " + defaultMaxBitrates[0]);
  
  			int bufSize = 1835;
  			boolean bitrateLevel41Limited = false;
  			boolean isXboxOneWebVideo = mediaRenderer.isXboxOne() && purpose() == VIDEO_WEBSTREAM_PLAYER;
  
  			/**
  			 * Although the maximum bitrate for H.264 Level 4.1 is
  			 * officially 50,000 kbit/s, some 4.1-capable renderers
  			 * like the PS3 stutter when video exceeds roughly 31,250
  			 * kbit/s.
  			 *
  			 * We also apply the correct buffer size in this section.
  			 */
  			if ((mediaRenderer.isTranscodeToH264() || mediaRenderer.isTranscodeToH265()) && !isXboxOneWebVideo) {
  				if (
  					mediaRenderer.isH264Level41Limited() &&
  					defaultMaxBitrates[0] > 31250
  				) {
  					defaultMaxBitrates[0] = 31250;
  					bitrateLevel41Limited = true;
  					LOGGER.trace("Adjusting the video bitrate limit to the H.264 Level 4.1-safe value of 31250");
  				}
  				bufSize = defaultMaxBitrates[0];
  			} else {
  				if (media.isHDVideo()) {
  					bufSize = defaultMaxBitrates[0] / 3;
  				}
  
  				if (bufSize > 7000) {
  					bufSize = 7000;
  				}
  
  				if (defaultMaxBitrates[1] > 0) {
  					bufSize = defaultMaxBitrates[1];
  				}
  
  				if (mediaRenderer.isDefaultVBVSize() && rendererMaxBitrates[1] == 0) {
  					bufSize = 1835;
  				}
  			}
  
  			if (!bitrateLevel41Limited) {
  				// Make room for audio
  				switch (audioType) {
  					case "pcm":
  						defaultMaxBitrates[0] -= 4600;
  						break;
  					case "dts":
  						defaultMaxBitrates[0] -= 1510;
  						break;
  					case "aac":
  					case "ac3":
  						defaultMaxBitrates[0] -= configuration.getAudioBitrate();
  						break;
  					default:
  						break;
  				}
  
  				// Round down to the nearest Mb
  				defaultMaxBitrates[0] = defaultMaxBitrates[0] / 1000 * 1000;
  
  				LOGGER.trace("Adjusting the video bitrate limit to " + defaultMaxBitrates[0] + " to make room for audio");
  			}
  
  			encodeSettings += ":vrc_maxrate=" + defaultMaxBitrates[0] + ":vrc_buf_size=" + bufSize;
  		}
  
  		return encodeSettings;
  	}
  
  	/*
  	 * Collapse the multiple internal ways of saying "subtitles are disabled" into a single method
  	 * which returns true if any of the following are true:
  	 *
  	 *     1) configuration.isDisableSubtitles()
  	 *     2) params.sid == null
  	 *     3) avisynth()
  	 */
  	private boolean isDisableSubtitles(OutputParams params) {
  		return configuration.isDisableSubtitles() || (params.sid == null) || avisynth();
  	}
  
  	@Override
  	public ProcessWrapper launchTranscode(
  		DLNAResource dlna,
  		DLNAMediaInfo media,
  		OutputParams params
  	) throws IOException {
  		PmsConfiguration prev = configuration;
  		configuration = (DeviceConfiguration) params.mediaRenderer;
  		params.manageFastStart();
  
  		boolean avisynth = avisynth();
  
  		final String filename = dlna.getSystemName();
  		setAudioAndSubs(filename, media, params);
  		String externalSubtitlesFileName = null;
  
  		if (params.sid != null && params.sid.isExternal()) {
  			if (params.sid.isExternalFileUtf16()) {
  				// convert UTF-16 -> UTF-8
  				File convertedSubtitles = new File(configuration.getTempFolder(), "utf8_" + params.sid.getExternalFile().getName());
  				FileUtil.convertFileFromUtf16ToUtf8(params.sid.getExternalFile(), convertedSubtitles);
  				externalSubtitlesFileName = ProcessUtil.getShortFileNameIfWideChars(convertedSubtitles.getAbsolutePath());
  			} else {
  				externalSubtitlesFileName = ProcessUtil.getShortFileNameIfWideChars(params.sid.getExternalFile().getAbsolutePath());
  			}
  		}
  
  		InputFile newInput = new InputFile();
  		newInput.setFilename(filename);
  		newInput.setPush(params.stdin);
  
  		dvd = false;
  
  		if (media != null && media.getDvdtrack() > 0) {
  			dvd = true;
  		}
  
  		ovccopy  = false;
  		pcm      = false;
  		ac3Remux = false;
  		dtsRemux = false;
  		wmv      = false;
  
  		int intOCW = 0;
  		int intOCH = 0;
  
  		try {
  			intOCW = Integer.parseInt(configuration.getMencoderOverscanCompensationWidth());
  		} catch (NumberFormatException e) {
  			LOGGER.error("Cannot parse configured MEncoder overscan compensation width: \"{}\"", configuration.getMencoderOverscanCompensationWidth());
  		}
  
  		try {
  			intOCH = Integer.parseInt(configuration.getMencoderOverscanCompensationHeight());
  		} catch (NumberFormatException e) {
  			LOGGER.error("Cannot parse configured MEncoder overscan compensation height: \"{}\"", configuration.getMencoderOverscanCompensationHeight());
  		}
  
  		/*
  		 * Check if the video track and the container report different aspect ratios
  		 */
  		boolean aspectRatiosMatch = true;
  		if (
  			media.getAspectRatioContainer() != null &&
  			media.getAspectRatioVideoTrack() != null &&
  			!media.getAspectRatioContainer().equals(media.getAspectRatioVideoTrack())
  		) {
  			aspectRatiosMatch = false;
  		}
  
  		// Decide whether to defer to tsMuxeR or continue to use MEncoder
  		boolean deferToTsmuxer = true;
  		String prependTraceReason = "Not muxing the video stream with tsMuxeR via MEncoder because ";
  		if (!configuration.isMencoderMuxWhenCompatible()) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "the user setting is disabled");
  		}
  		if (deferToTsmuxer == true && !configuration.getHideTranscodeEnabled() && dlna.isNoName() && (dlna.getParent() instanceof FileTranscodeVirtualFolder)) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "the file is being played via a MEncoder entry in the transcode folder.");
  		}
  		if (deferToTsmuxer == true && !params.mediaRenderer.isMuxH264MpegTS()) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "the renderer does not support H.264 inside MPEG-TS.");
  		}
  		if (deferToTsmuxer == true && params.sid != null) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "we need to burn subtitles.");
  		}
  		if (deferToTsmuxer == true && dvd) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "this is a DVD track.");
  		}
  		if (deferToTsmuxer == true && avisynth()) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "we are using AviSynth.");
  		}
  		if (deferToTsmuxer == true && params.mediaRenderer.isH264Level41Limited() && !media.isVideoWithinH264LevelLimits(newInput, params.mediaRenderer)) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "the video stream is not within H.264 level limits for this renderer.");
  		}
  		if (deferToTsmuxer == true && !media.isMuxable(params.mediaRenderer)) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "the video stream is not muxable to this renderer");
  		}
  		if (deferToTsmuxer == true && intOCW > 0 && intOCH > 0) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "we need to transcode to apply overscan compensation.");
  		}
  		if (deferToTsmuxer == true && !aspectRatiosMatch) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "we need to transcode to apply the correct aspect ratio.");
  		}
  		if (
  			deferToTsmuxer == true &&
  			!params.mediaRenderer.isPS3() &&
  			media.isWebDl(filename, params)
  		) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "the version of tsMuxeR supported by this renderer does not support WEB-DL files.");
  		}
  		if (deferToTsmuxer == true && "bt.601".equals(media.getMatrixCoefficients())) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "the colorspace probably isn't supported by the renderer.");
  		}
  		if (deferToTsmuxer == true && params.mediaRenderer.isKeepAspectRatio() && !"16:9".equals(media.getAspectRatioContainer())) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "the renderer needs us to add borders so it displays the correct aspect ratio of " + media.getAspectRatioContainer() + ".");
  		}
  		if (deferToTsmuxer == true && !params.mediaRenderer.isResolutionCompatibleWithRenderer(media.getWidth(), media.getHeight())) {
  			deferToTsmuxer = false;
  			LOGGER.trace(prependTraceReason + "the resolution is incompatible with the renderer.");
  		}
  		if (deferToTsmuxer) {
  			String expertOptions[] = getSpecificCodecOptions(
  				configuration.getMencoderCodecSpecificConfig(),
  				media,
  				params,
  				filename,
  				externalSubtitlesFileName,
  				configuration.isMencoderIntelligentSync(),
  				false
  			);
  
  			boolean nomux = false;
  
  			for (String s : expertOptions) {
  				if (s.equals("-nomux")) {
  					nomux = true;
  				}
  			}
  
  			if (!nomux) {
  				TsMuxeRVideo tv = new TsMuxeRVideo();
  				params.forceFps = media.getValidFps(false);
  
  				if (media.getCodecV() != null) {
  					if (media.isH264()) {
  						params.forceType = "V_MPEG4/ISO/AVC";
  					} else if (media.getCodecV().startsWith("mpeg2")) {
  						params.forceType = "V_MPEG-2";
  					} else if (media.getCodecV().equals("vc1")) {
  						params.forceType = "V_MS/VFW/WVC1";
  					}
  				}
  
  				return tv.launchTranscode(dlna, media, params);
  			}
  		} else if (params.sid == null && dvd && configuration.isMencoderRemuxMPEG2() && params.mediaRenderer.isMpeg2Supported()) {
  			String expertOptions[] = getSpecificCodecOptions(
  				configuration.getMencoderCodecSpecificConfig(),
  				media,
  				params,
  				filename,
  				externalSubtitlesFileName,
  				configuration.isMencoderIntelligentSync(),
  				false
  			);
  
  			boolean nomux = false;
  
  			for (String s : expertOptions) {
  				if (s.equals("-nomux")) {
  					nomux = true;
  				}
  			}
  
  			if (!nomux) {
  				ovccopy = true;
  			}
  		}
  
  		isTranscodeToMPEGTS = params.mediaRenderer.isTranscodeToMPEGTS();
  		isTranscodeToH264   = params.mediaRenderer.isTranscodeToH264() || params.mediaRenderer.isTranscodeToH265();
  		isTranscodeToAAC    = params.mediaRenderer.isTranscodeToAAC();
  
  		final boolean isXboxOneWebVideo = params.mediaRenderer.isXboxOne() && purpose() == VIDEO_WEBSTREAM_PLAYER;
  
  		String vcodec = "mpeg2video";
  		if (isTranscodeToH264) {
  			vcodec = "libx264";
  		} else if (
  			(
  				params.mediaRenderer.isTranscodeToWMV() &&
  				!params.mediaRenderer.isXbox360()
  			) ||
  			isXboxOneWebVideo
  		) {
  			wmv = true;
  			vcodec = "wmv2";
  		}
  
  		// Default: Empty string
  		String rendererMencoderOptions = params.mediaRenderer.getCustomMencoderOptions();
  
  		/**
  		 * Ignore the renderer's custom MEncoder options if a) we're streaming a DVD (i.e. via dvd://)
  		 * or b) the renderer's MEncoder options contain overscan settings (those are handled
  		 * separately)
  		 */
  		// XXX we should weed out the unused/unwanted settings and keep the rest
  		// (see sanitizeArgs()) rather than ignoring the options entirely
  		if (rendererMencoderOptions.contains("expand=") && dvd) {
  			rendererMencoderOptions = "";
  		}
  
  		// Default: Empty string
  		String globalMencoderOptions = configuration.getMencoderCustomOptions();
  
  		String combinedCustomOptions = defaultString(globalMencoderOptions) +
  			" " +
  			defaultString(rendererMencoderOptions);
  
  		/**
  		 * Disable AC3 remux for stereo tracks with 384 kbits bitrate and PS3 renderer (PS3 FW bug?)
  		 *
  		 * Commented out until we can find a way to detect when a video has an audio track that switches from 2 to 6 channels
  		 * because MEncoder can't handle those files, which are very common these days.
  		boolean ps3_and_stereo_and_384_kbits = params.aid != null &&
  			(params.mediaRenderer.isPS3() && params.aid.getAudioProperties().getNumberOfChannels() == 2) &&
  			(params.aid.getBitRate() > 370000 && params.aid.getBitRate() < 400000);
  		 */
  
  		final boolean isTsMuxeRVideoEngineEnabled = configuration.getEnginesAsList(PMS.get().getRegistry()).contains(TsMuxeRVideo.ID);
  		final boolean mencoderAC3RemuxAudioDelayBug = (params.aid != null) && (params.aid.getAudioProperties().getAudioDelay() != 0) && (params.timeseek == 0);
  
  		encodedAudioPassthrough = isTsMuxeRVideoEngineEnabled &&
  			configuration.isEncodedAudioPassthrough() &&
  			params.mediaRenderer.isWrapEncodedAudioIntoPCM() &&
  			(
  				!dvd ||
  				configuration.isMencoderRemuxMPEG2()
  			) &&
  			params.aid != null && 
  			params.aid.isNonPCMEncodedAudio() && 
  			!avisynth() && 
  			params.mediaRenderer.isMuxLPCMToMpeg();
  
  		if (
  			configuration.isAudioRemuxAC3() &&
  			params.aid != null &&
  			params.aid.isAC3() &&
  			!avisynth() &&
  			params.mediaRenderer.isTranscodeToAC3() &&
  			!configuration.isMEncoderNormalizeVolume() &&
  			!combinedCustomOptions.contains("acodec=") &&
  			!encodedAudioPassthrough &&
  			!isXboxOneWebVideo &&
  			params.aid.getAudioProperties().getNumberOfChannels() <= configuration.getAudioChannelCount()
  		) {
  			ac3Remux = true;
  		} else {
  			// Now check for DTS remux and LPCM streaming
  			dtsRemux = isTsMuxeRVideoEngineEnabled &&
  				configuration.isAudioEmbedDtsInPcm() &&
  				(
  					!dvd ||
  					configuration.isMencoderRemuxMPEG2()
  				) && params.aid != null &&
  				params.aid.isDTS() &&
  				!avisynth() &&
  				params.mediaRenderer.isDTSPlayable() &&
  				!combinedCustomOptions.contains("acodec=");
  			pcm = isTsMuxeRVideoEngineEnabled &&
  				configuration.isAudioUsePCM() &&
  				(
  					!dvd ||
  					configuration.isMencoderRemuxMPEG2()
  				)
  				// Disable LPCM transcoding for MP4 container with non-H.264 video as workaround for MEncoder's A/V sync bug
  				&& !(media.getContainer().equals("mp4") && !media.isH264())
  				&& params.aid != null &&
  				(
  					(params.aid.isDTS() && params.aid.getAudioProperties().getNumberOfChannels() <= 6) || // disable 7.1 DTS-HD => LPCM because of channels mapping bug
  					params.aid.isLossless() ||
  					params.aid.isTrueHD() ||
  					(
  						!configuration.isMencoderUsePcmForHQAudioOnly() &&
  						(
  							params.aid.isAC3() ||
  							params.aid.isMP3() ||
  							params.aid.isAAC() ||
  							params.aid.isVorbis() ||
  							// Disable WMA to LPCM transcoding because of mencoder's channel mapping bug
  							// (see CodecUtil.getMixerOutput)
  							// params.aid.isWMA() ||
  							params.aid.isMpegAudio()
  						)
  					)
  				) && params.mediaRenderer.isLPCMPlayable() &&
  				!combinedCustomOptions.contains("acodec=");
  		}
  
  		if (dtsRemux || pcm || encodedAudioPassthrough) {
  			params.losslessaudio = true;
  			params.forceFps = media.getValidFps(false);
  		}
  
  		// MPEG-2 remux still buggy with MEncoder
  		// TODO when we can still use it?
  		ovccopy = false;
  
  		if (pcm && avisynth()) {
  			params.avidemux = true;
  		}
  
  		String add = "";
  		if (!combinedCustomOptions.contains("-lavdopts")) {
  			add = " -lavdopts debug=0";
  		}
  
  		int channels;
  		if (ac3Remux) {
  			channels = params.aid.getAudioProperties().getNumberOfChannels(); // AC-3 remux
  		} else if (dtsRemux || encodedAudioPassthrough || (!params.mediaRenderer.isXbox360() && wmv)) {
  			channels = 2;
  		} else if (pcm) {
  			channels = params.aid.getAudioProperties().getNumberOfChannels();
  		} else {
  			/**
  			 * Note: MEncoder will output 2 audio channels if the input video had 2 channels
  			 * regardless of us telling it to output 6 (unlike FFmpeg which will output 6).
  			 */
  			channels = configuration.getAudioChannelCount(); // 5.1 max for AC-3 encoding
  		}
  		String channelsString = "-channels " + channels;
  		if (combinedCustomOptions.contains("-channels")) {
  			channelsString = "";
  		}
  
  		StringTokenizer st = new StringTokenizer(
  			channelsString +
  			(isNotBlank(globalMencoderOptions) ? " " + globalMencoderOptions : "") +
  			(isNotBlank(rendererMencoderOptions) ? " " + rendererMencoderOptions : "") +
  			add,
  			" "
  		);
  
  		// XXX why does this field (which is used to populate the array returned by args(),
  		// called below) store the renderer-specific (i.e. not global) MEncoder options?
  		overriddenMainArgs = new String[st.countTokens()];
  
  		{
  			int nThreads = (dvd || filename.toLowerCase().endsWith("dvr-ms")) ?
  				1 :
  				configuration.getMencoderMaxThreads();
  
  			// MEncoder loses audio/video sync if more than 4 decoder (lavdopts) threads are used.
  			// Multithreading for decoding offers little performance gain anyway so it's not a big deal.
  			if (nThreads > 4) {
  				nThreads = 4;
  			}
  
  			boolean handleToken = false;
  			int i = 0;
  
  			while (st.hasMoreTokens()) {
  				String token = st.nextToken().trim();
  
  				if (handleToken) {
  					token += ":threads=" + nThreads;
  
  					if (configuration.getSkipLoopFilterEnabled() && !avisynth()) {
  						token += ":skiploopfilter=all";
  					}
  
  					handleToken = false;
  				}
  
  				if (token.toLowerCase().contains("lavdopts")) {
  					handleToken = true;
  				}
  
  				overriddenMainArgs[i++] = token;
  			}
  		}
  
  		String vcodecString = ":vcodec=" + vcodec;
  		if (combinedCustomOptions.contains("vcodec=")) {
  			vcodecString = "";
  		}
  
  		if (
  			(configuration.getx264ConstantRateFactor() != null && isTranscodeToH264) ||
  			(configuration.getMPEG2MainSettings() != null && !isTranscodeToH264)
  		) {
  			// Ditlew - WDTV Live (+ other byte asking clients), CBR. This probably ought to be placed in addMaximumBitrateConstraints(..)
  			int cbr_bitrate = params.mediaRenderer.getCBRVideoBitrate();
  			String cbr_settings = (cbr_bitrate > 0) ?
  				":vrc_buf_size=5000:vrc_minrate=" + cbr_bitrate + ":vrc_maxrate=" + cbr_bitrate + ":vbitrate=" + ((cbr_bitrate > 16000) ? cbr_bitrate * 1000 : cbr_bitrate) :
  				"";
  
  			// Set audio codec and bitrate if audio is being transcoded
  			String acodec   = "";
  			String abitrate = "";
  			if (!ac3Remux && !dtsRemux && !isTranscodeToAAC) {
  				// Set the audio codec used by Lavc
  				if (!combinedCustomOptions.contains("acodec=")) {
  					acodec = ":acodec=";
  					if (wmv && !params.mediaRenderer.isXbox360()) {
  						acodec += "wmav2";
  					} else {
  						acodec = cbr_settings + acodec;
  						if (params.mediaRenderer.isTranscodeToAAC()) {
  							acodec += "libfaac";
  						} else if (configuration.isMencoderAc3Fixed()) {
  							acodec += "ac3_fixed";
  						} else {
  							acodec += "ac3";
  						}
  					}
  				}
  
  				// Set the audio bitrate used by Lavc
  				if (!combinedCustomOptions.contains("abitrate=")) {
  					abitrate = ":abitrate=";
  					if (wmv && !params.mediaRenderer.isXbox360()) {
  						abitrate += "448";
  					} else {
  						abitrate += CodecUtil.getAC3Bitrate(configuration, params.aid);
  					}
  				}
  			}
  
  			// Find out the maximum bandwidth we are supposed to use
  			int defaultMaxBitrates[] = getVideoBitrateConfig(configuration.getMaximumBitrate());
  			int rendererMaxBitrates[] = new int[2];
  
  			if (isNotEmpty(params.mediaRenderer.getMaxVideoBitrate())) {
  				rendererMaxBitrates = getVideoBitrateConfig(params.mediaRenderer.getMaxVideoBitrate());
  			}
  
  			if ((rendererMaxBitrates[0] > 0) && (rendererMaxBitrates[0] < defaultMaxBitrates[0])) {
  				defaultMaxBitrates = rendererMaxBitrates;
  			}
  
  			int maximumBitrate = defaultMaxBitrates[0];
  
  			// Set which audio codec to use
  			String audioType = "ac3";
  			if (dtsRemux) {
  				audioType = "dts";
  			} else if (pcm || encodedAudioPassthrough) {
  				audioType = "pcm";
  			} else if (params.mediaRenderer.isTranscodeToAAC()) {
  				audioType = "aac";
  			}
  
  			String encodeSettings = "";
  
  			/**
  			 * Fixes aspect ratios on Sony TVs
  			 */
  			String aspectRatioLavcopts = "autoaspect=1";
  			if (
  				!dvd &&
  				(
  					params.mediaRenderer.isKeepAspectRatio() &&
  					!"16:9".equals(media.getAspectRatioContainer())
  				) &&
  				!configuration.isMencoderScaler()
  			) {
  				aspectRatioLavcopts = "aspect=16/9";
  			}
  
  			if (isXboxOneWebVideo || (configuration.getMPEG2MainSettings() != null && !isTranscodeToH264)) {
  				// Set MPEG-2 video quality
  				String mpeg2Options = configuration.getMPEG2MainSettings();
  				String mpeg2OptionsRenderer = params.mediaRenderer.getCustomMEncoderMPEG2Options();
  
  				// Renderer settings take priority over user settings
  				if (isNotBlank(mpeg2OptionsRenderer)) {
  					mpeg2Options = mpeg2OptionsRenderer;
  				} else {
  					// Remove comment from the value
  					if (mpeg2Options.contains("/*")) {
  						mpeg2Options = mpeg2Options.substring(mpeg2Options.indexOf("/*"));
  					}
  
  					// Determine a good quality setting based on video attributes
  					if (mpeg2Options.contains("Automatic")) {
  						mpeg2Options = "keyint=5:vqscale=1:vqmin=2:vqmax=3";
  
  						// It has been reported that non-PS3 renderers prefer keyint 5 but prefer it for PS3 because it lowers the average bitrate
  						if (params.mediaRenderer.isPS3()) {
  							mpeg2Options = "keyint=25:vqscale=1:vqmin=2:vqmax=3";
  						}
  
  						if (mpeg2Options.contains("Wireless") || maximumBitrate < 70) {
  							// Lower quality for 720p+ content
  