]> git.xonotic.org Git - xonotic/xonotic.git/blobdiff - misc/tools/NexuizDemoRecorder/plugins/virtualdub/src/main/java/com/nexuiz/demorecorder/application/plugins/impl/virtualdub/VirtualDubPlugin.java
fix lots of CRLFs
[xonotic/xonotic.git] / misc / tools / NexuizDemoRecorder / plugins / virtualdub / src / main / java / com / nexuiz / demorecorder / application / plugins / impl / virtualdub / VirtualDubPlugin.java
index 6f95540c284e7df862a0b6980bf618ef273cf86e..ddea72a4cb63b3d706f0fb2d0c91ac85210473bb 100644 (file)
-package com.nexuiz.demorecorder.application.plugins.impl.virtualdub;\r
-\r
-import java.io.BufferedReader;\r
-import java.io.BufferedWriter;\r
-import java.io.File;\r
-import java.io.FileWriter;\r
-import java.io.IOException;\r
-import java.io.InputStreamReader;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-import java.util.Properties;\r
-\r
-import com.nexuiz.demorecorder.application.DemoRecorderApplication;\r
-import com.nexuiz.demorecorder.application.DemoRecorderException;\r
-import com.nexuiz.demorecorder.application.DemoRecorderUtils;\r
-import com.nexuiz.demorecorder.application.jobs.RecordJob;\r
-import com.nexuiz.demorecorder.application.plugins.EncoderPlugin;\r
-import com.nexuiz.demorecorder.application.plugins.EncoderPluginException;\r
-\r
-public class VirtualDubPlugin implements EncoderPlugin {\r
-       \r
-       private static final String PLUGIN_NAME = "Virtual Dub";\r
-       \r
-       private static class Preferences {\r
-               public static final String ENABLED = "Enabled";\r
-               public static final String VIRTUAL_DUB_BINARY_PATH = "Path to vdub.exe";\r
-               public static final String VCF_PER_JOB_LIMIT = "Max. number of VCFs per job";\r
-               public static final String OUTPUT_FILE_MODE = "Output as suffix (0) or file (1)";\r
-               public static final String EXTRA_OPTIONS = "Show extra options";\r
-               \r
-               public static final String[] GLOBAL_PREFERENCES_ORDER = {\r
-                       ENABLED,\r
-                       VIRTUAL_DUB_BINARY_PATH,\r
-                       VCF_PER_JOB_LIMIT,\r
-                       OUTPUT_FILE_MODE,\r
-                       EXTRA_OPTIONS\r
-               };\r
-               \r
-               //job-specific preferences\r
-               public static final String CLEAR_JOBCONTROL = "Clear VDub job control on first VCF";\r
-               public static final String RENDER_OUTPUT = "VDub renders queued jobs";\r
-               public static final String VCF_PATH = "Path to VCF file "; //x will be attached, e.g. "Path to VCF file 1"\r
-               public static final String OUTPUT_SUFFIX = "Suffix for output file "; //x will be attached, e.g. "Suffix for output file 1"\r
-               public static final String OUTPUT_FILE = "Output file "; //x will be attached\r
-               public static final String USE_ENCODED_VIDEO = "<HTML><BODY>Use encoded video from VCF "; //x will be attached\r
-               public static final String USE_ENCODED_VIDEO_2 = "<BR>for consecutive VCFs</BODY></HTML>";\r
-               public static final String DELETE_ORIG_FILE = "Delete orig. file after processing VCF "; //x will be attached\r
-       }\r
-       \r
-       private DemoRecorderApplication appLayer = null;\r
-       private Properties globalDefaultPreferences = new Properties();\r
-       \r
-       public VirtualDubPlugin() {\r
-               this.createPreferenceDefaultValues();\r
-       }\r
-\r
-       @Override\r
-       public void executeEncoder(RecordJob job) throws EncoderPluginException {\r
-               this.checkAppLayer();\r
-               if (!this.isEnabled()) {\r
-                       return;\r
-               }\r
-               \r
-               if (job.getActualVideoDestination() == null) {\r
-                       //should never happen... but just to make sure!\r
-                       throw new EncoderPluginException("Actual video destination is not set (should have been set when processing the job)");\r
-               }\r
-               \r
-               if (!job.getActualVideoDestination().exists()) {\r
-                       throw new EncoderPluginException("Could not locate video file (source) at location "\r
-                                       + job.getActualVideoDestination().getAbsolutePath());\r
-               }\r
-               \r
-               String limitStr = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VCF_PER_JOB_LIMIT);\r
-               int vcfCounter;\r
-               try {\r
-                       vcfCounter = Integer.valueOf(limitStr);\r
-               } catch (NumberFormatException e) {\r
-                       throw new EncoderPluginException("Invalid value \"" + limitStr + "\" for setting " + Preferences.VCF_PER_JOB_LIMIT);\r
-               }\r
-               \r
-               //check vdub.exe\r
-               String vDubBinary = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VIRTUAL_DUB_BINARY_PATH);\r
-               File vDubBinaryFile = new File(vDubBinary);\r
-               if (!vDubBinaryFile.exists() || !vDubBinaryFile.canExecute()) {\r
-                       throw new EncoderPluginException("Invalid location for the vdub.exe: " + vDubBinary);\r
-               }\r
-               \r
-               this.doEncoding(job, vcfCounter);\r
-       }\r
-\r
-       @Override\r
-       public Properties getGlobalPreferences() {\r
-               return this.globalDefaultPreferences;\r
-       }\r
-\r
-       @Override\r
-       public String[] getGlobalPreferencesOrder() {\r
-               return Preferences.GLOBAL_PREFERENCES_ORDER;\r
-       }\r
-\r
-       @Override\r
-       public Properties getJobSpecificPreferences() {\r
-               this.checkAppLayer();\r
-               Properties jobSpecificPreferences = new Properties();\r
-               \r
-               //static properties\r
-               jobSpecificPreferences.setProperty(Preferences.CLEAR_JOBCONTROL, "true");\r
-               jobSpecificPreferences.setProperty(Preferences.RENDER_OUTPUT, "true");\r
-               \r
-               //dynamic properties\r
-               String limitStr = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VCF_PER_JOB_LIMIT);\r
-               try {\r
-                       int limit = Integer.valueOf(limitStr);\r
-                       if (limit > 0) {\r
-                               for (int i = 1; i <= limit; i++) {\r
-                                       jobSpecificPreferences.setProperty(Preferences.VCF_PATH + i, "filechooser");\r
-                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.OUTPUT_FILE_MODE))) {\r
-                                               //filechooser\r
-                                               jobSpecificPreferences.setProperty(Preferences.OUTPUT_FILE + i, "filechooser");\r
-                                       } else {\r
-                                               //suffix\r
-                                               jobSpecificPreferences.setProperty(Preferences.OUTPUT_SUFFIX + i, "_vdub" + i);\r
-                                       }\r
-                                       \r
-                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.EXTRA_OPTIONS))) {\r
-                                               String useEncStringKey = Preferences.USE_ENCODED_VIDEO + i + Preferences.USE_ENCODED_VIDEO_2;\r
-                                               jobSpecificPreferences.setProperty(useEncStringKey, "false");\r
-                                               jobSpecificPreferences.setProperty(Preferences.DELETE_ORIG_FILE + i, "false");\r
-                                       }\r
-                               }\r
-                       }\r
-               } catch (NumberFormatException e) {\r
-                       throw new DemoRecorderException("Invalid value \"" + limitStr + "\" for setting " + Preferences.VCF_PER_JOB_LIMIT);\r
-               }\r
-               \r
-               return jobSpecificPreferences;\r
-       }\r
-       \r
-       @Override\r
-       public String[] getJobSpecificPreferencesOrder() {\r
-               this.checkAppLayer();\r
-               List<String> preferencesOrderList = new ArrayList<String>();\r
-               \r
-               //static properties\r
-               preferencesOrderList.add(Preferences.CLEAR_JOBCONTROL);\r
-               preferencesOrderList.add(Preferences.RENDER_OUTPUT);\r
-               \r
-               //dynamic properties\r
-               String limitStr = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VCF_PER_JOB_LIMIT);\r
-               try {\r
-                       int limit = Integer.valueOf(limitStr);\r
-                       if (limit > 0) {\r
-                               for (int i = 1; i <= limit; i++) {\r
-                                       preferencesOrderList.add(Preferences.VCF_PATH + i);\r
-                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.OUTPUT_FILE_MODE))) {\r
-                                               //filechooser\r
-                                               preferencesOrderList.add(Preferences.OUTPUT_FILE + i);\r
-                                       } else {\r
-                                               //suffix\r
-                                               preferencesOrderList.add(Preferences.OUTPUT_SUFFIX + i);\r
-                                       }\r
-                                       \r
-                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.EXTRA_OPTIONS))) {\r
-                                               String useEncStringKey = Preferences.USE_ENCODED_VIDEO + i + Preferences.USE_ENCODED_VIDEO_2;\r
-                                               preferencesOrderList.add(useEncStringKey);\r
-                                               preferencesOrderList.add(Preferences.DELETE_ORIG_FILE + i);\r
-                                       }\r
-                               }\r
-                       }\r
-               } catch (NumberFormatException e) {\r
-                       throw new DemoRecorderException("Invalid value \"" + limitStr + "\" for setting " + Preferences.VCF_PER_JOB_LIMIT);\r
-               }\r
-               \r
-               Object[] arr = preferencesOrderList.toArray();\r
-               String[] stringArr = new String[arr.length];\r
-               for (int i = 0; i < arr.length; i++) {\r
-                       stringArr[i] = (String) arr[i];\r
-               }\r
-               \r
-               return stringArr;\r
-       }\r
-\r
-       @Override\r
-       public String getName() {\r
-               return PLUGIN_NAME;\r
-       }\r
-\r
-       @Override\r
-       public boolean isEnabled() {\r
-               this.checkAppLayer();\r
-               String enabledString = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.ENABLED);\r
-               return Boolean.valueOf(enabledString);\r
-       }\r
-\r
-       @Override\r
-       public void setApplicationLayer(DemoRecorderApplication appLayer) {\r
-               this.appLayer = appLayer;\r
-       }\r
-       \r
-       private void checkAppLayer() {\r
-               if (this.appLayer == null) {\r
-                       throw new DemoRecorderException("Error in plugin " + PLUGIN_NAME + "! Application layer not set!");\r
-               }\r
-       }\r
-       \r
-       private void createPreferenceDefaultValues() {\r
-               this.globalDefaultPreferences.setProperty(Preferences.ENABLED, "false");\r
-               this.globalDefaultPreferences.setProperty(Preferences.VIRTUAL_DUB_BINARY_PATH, "filechooser");\r
-               this.globalDefaultPreferences.setProperty(Preferences.VCF_PER_JOB_LIMIT, "1");\r
-               this.globalDefaultPreferences.setProperty(Preferences.OUTPUT_FILE_MODE, "false");\r
-               this.globalDefaultPreferences.setProperty(Preferences.EXTRA_OPTIONS, "false");\r
-       }\r
-       \r
-       private void doEncoding(RecordJob job, int vcfCounter) throws EncoderPluginException {\r
-               boolean firstValidVCF = true;\r
-               for (int i = 1; i <= vcfCounter; i++) {\r
-                       Properties jobSpecificSettings = job.getEncoderPluginSettings(this);\r
-                       String path = jobSpecificSettings.getProperty(Preferences.VCF_PATH + i);\r
-                       if (path != null) {\r
-                               File vcfFile = new File(path);\r
-                               if (vcfFile.exists()) {\r
-                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.OUTPUT_FILE_MODE))) {\r
-                                               //filechooser\r
-                                               String outputPath = jobSpecificSettings.getProperty(Preferences.OUTPUT_FILE + i, "filechooser");\r
-                                               if (outputPath == null || outputPath.equals("") || outputPath.equals("filechoose")) {\r
-                                                       //user has not yet selected a file\r
-                                                       continue;\r
-                                               }\r
-                                       } else {\r
-                                               //suffix\r
-                                               String suffix = jobSpecificSettings.getProperty(Preferences.OUTPUT_SUFFIX + i);\r
-                                               if (suffix == null || suffix.equals("")) {\r
-                                                       continue;\r
-                                               }\r
-                                       }\r
-                                       BufferedWriter logWriter = this.getLogWriter(job.getJobName(), i);\r
-                                       this.executeVDub(job, i, firstValidVCF, logWriter);\r
-                                       firstValidVCF = false;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       private void executeVDub(RecordJob job, int index, boolean firstValidVCF, BufferedWriter logWriter) throws EncoderPluginException {\r
-               String shellString = "";\r
-               Properties jobSpecificSettings = job.getEncoderPluginSettings(this);\r
-               File vcfFile = new File(jobSpecificSettings.getProperty(Preferences.VCF_PATH + index));\r
-               File sourceFile = job.getActualVideoDestination();\r
-               \r
-               String vDubBinary = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VIRTUAL_DUB_BINARY_PATH);\r
-               shellString += '"' + vDubBinary.trim() + '"';\r
-               \r
-               shellString += " /s " + '"' + vcfFile.getAbsolutePath() + '"';\r
-               \r
-               boolean clearJobControl = Boolean.valueOf(jobSpecificSettings.getProperty(Preferences.CLEAR_JOBCONTROL, "true"));\r
-               if (clearJobControl && firstValidVCF) {\r
-                       shellString += " /c";\r
-               }\r
-               \r
-               String outputFilePath = this.getOutputFilePath(job, index);\r
-               File outputFile = new File(outputFilePath);\r
-               shellString += " /p " + '"' + sourceFile.getAbsolutePath() + '"';\r
-               shellString += " " + '"' + outputFilePath + '"';\r
-               \r
-               boolean renderOutput = Boolean.valueOf(jobSpecificSettings.getProperty(Preferences.RENDER_OUTPUT, "true"));\r
-               if (renderOutput) {\r
-                       shellString += " /r";\r
-               }\r
-               \r
-               shellString += " /x";\r
-               \r
-               try {\r
-                       logWriter.write("Executing commandline: " + shellString);\r
-                       logWriter.newLine();\r
-                       File vdubDir = new File(vDubBinary).getParentFile();\r
-                       Process vDubProc;\r
-                       vDubProc = Runtime.getRuntime().exec(shellString, null, vdubDir);\r
-                       vDubProc.getOutputStream();\r
-                       InputStreamReader isr = new InputStreamReader(vDubProc.getInputStream());\r
-                       BufferedReader bufferedInputStream = new BufferedReader(isr);\r
-                       String currentLine;\r
-                       while ((currentLine = bufferedInputStream.readLine()) != null) {\r
-                               logWriter.write(currentLine);\r
-                               logWriter.newLine();\r
-                       }\r
-                       InputStreamReader isrErr = new InputStreamReader(vDubProc.getErrorStream());\r
-                       BufferedReader bufferedInputStreamErr = new BufferedReader(isrErr);\r
-                       while ((currentLine = bufferedInputStreamErr.readLine()) != null) {\r
-                               logWriter.write(currentLine);\r
-                               logWriter.newLine();\r
-                       }\r
-                       logWriter.close();\r
-                       \r
-               } catch (IOException e) {\r
-                       throw new EncoderPluginException("I/O Exception occurred when trying to execute the VDub binary or logging output", e);\r
-               }\r
-               \r
-               //extra options: replace original video with encoded one, possibly delete original one\r
-               if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.EXTRA_OPTIONS))) {\r
-                       String useEncStringKey = Preferences.USE_ENCODED_VIDEO + index + Preferences.USE_ENCODED_VIDEO_2;\r
-                       String useEncVideo = jobSpecificSettings.getProperty(useEncStringKey);\r
-                       File origFile = job.getActualVideoDestination();\r
-                       if (useEncVideo != null && Boolean.valueOf(useEncVideo)) {\r
-                               job.setActualVideoDestination(outputFile);\r
-                       }\r
-                       \r
-                       String deleteOrigFile = jobSpecificSettings.getProperty(Preferences.DELETE_ORIG_FILE + index);\r
-                       if (deleteOrigFile != null && Boolean.valueOf(deleteOrigFile)) {\r
-                               //only delete the original file if the encoded one exists:\r
-                               if (outputFile.exists() && outputFile.length() > 0) {\r
-                                       origFile.delete();\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       private String getOutputFilePath(RecordJob job, int index) {\r
-               File sourceFile = job.getActualVideoDestination();\r
-               String ext = DemoRecorderUtils.getFileExtension(sourceFile);\r
-               String outputFilePath;\r
-               Properties jobSpecificSettings = job.getEncoderPluginSettings(this);\r
-               if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.OUTPUT_FILE_MODE))) {\r
-                       //filechooser\r
-                       outputFilePath = jobSpecificSettings.getProperty(Preferences.OUTPUT_FILE + index);\r
-               } else {\r
-                       //suffix\r
-                       outputFilePath = sourceFile.getAbsolutePath();\r
-                       String suffix = jobSpecificSettings.getProperty(Preferences.OUTPUT_SUFFIX + index);\r
-                       int idx = outputFilePath.indexOf("." + ext);\r
-                       outputFilePath = outputFilePath.substring(0, idx);\r
-                       outputFilePath += suffix + "." + ext;\r
-               }\r
-               \r
-               return outputFilePath;\r
-       }\r
-       \r
-       private BufferedWriter getLogWriter(String jobName, int vcfIndex) throws EncoderPluginException {\r
-               File logDir = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.LOGS_DIRNAME, "");\r
-               if (jobName == null || jobName.equals("")) {\r
-                       jobName = "unnamed_job";\r
-               }\r
-               String path = logDir.getAbsolutePath() + File.separator + PLUGIN_NAME + '_' + jobName + '_' + "vcf" + vcfIndex + ".log";\r
-               File logFile = new File(path);\r
-               if (!DemoRecorderUtils.attemptFileCreation(logFile)) {\r
-                       throw new EncoderPluginException("Could not create log file for VDub job at location: " + path);\r
-               }\r
-               try {\r
-                       FileWriter fileWriter = new FileWriter(logFile);\r
-                       return new BufferedWriter(fileWriter);\r
-               } catch (IOException e) {\r
-                       throw new EncoderPluginException("Could not create log file for VDub job at location: " + path, e);\r
-               }\r
-       }\r
-}\r
+package com.nexuiz.demorecorder.application.plugins.impl.virtualdub;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import com.nexuiz.demorecorder.application.DemoRecorderApplication;
+import com.nexuiz.demorecorder.application.DemoRecorderException;
+import com.nexuiz.demorecorder.application.DemoRecorderUtils;
+import com.nexuiz.demorecorder.application.jobs.RecordJob;
+import com.nexuiz.demorecorder.application.plugins.EncoderPlugin;
+import com.nexuiz.demorecorder.application.plugins.EncoderPluginException;
+
+public class VirtualDubPlugin implements EncoderPlugin {
+       
+       private static final String PLUGIN_NAME = "Virtual Dub";
+       
+       private static class Preferences {
+               public static final String ENABLED = "Enabled";
+               public static final String VIRTUAL_DUB_BINARY_PATH = "Path to vdub.exe";
+               public static final String VCF_PER_JOB_LIMIT = "Max. number of VCFs per job";
+               public static final String OUTPUT_FILE_MODE = "Output as suffix (0) or file (1)";
+               public static final String EXTRA_OPTIONS = "Show extra options";
+               
+               public static final String[] GLOBAL_PREFERENCES_ORDER = {
+                       ENABLED,
+                       VIRTUAL_DUB_BINARY_PATH,
+                       VCF_PER_JOB_LIMIT,
+                       OUTPUT_FILE_MODE,
+                       EXTRA_OPTIONS
+               };
+               
+               //job-specific preferences
+               public static final String CLEAR_JOBCONTROL = "Clear VDub job control on first VCF";
+               public static final String RENDER_OUTPUT = "VDub renders queued jobs";
+               public static final String VCF_PATH = "Path to VCF file "; //x will be attached, e.g. "Path to VCF file 1"
+               public static final String OUTPUT_SUFFIX = "Suffix for output file "; //x will be attached, e.g. "Suffix for output file 1"
+               public static final String OUTPUT_FILE = "Output file "; //x will be attached
+               public static final String USE_ENCODED_VIDEO = "<HTML><BODY>Use encoded video from VCF "; //x will be attached
+               public static final String USE_ENCODED_VIDEO_2 = "<BR>for consecutive VCFs</BODY></HTML>";
+               public static final String DELETE_ORIG_FILE = "Delete orig. file after processing VCF "; //x will be attached
+       }
+       
+       private DemoRecorderApplication appLayer = null;
+       private Properties globalDefaultPreferences = new Properties();
+       
+       public VirtualDubPlugin() {
+               this.createPreferenceDefaultValues();
+       }
+
+       @Override
+       public void executeEncoder(RecordJob job) throws EncoderPluginException {
+               this.checkAppLayer();
+               if (!this.isEnabled()) {
+                       return;
+               }
+               
+               if (job.getActualVideoDestination() == null) {
+                       //should never happen... but just to make sure!
+                       throw new EncoderPluginException("Actual video destination is not set (should have been set when processing the job)");
+               }
+               
+               if (!job.getActualVideoDestination().exists()) {
+                       throw new EncoderPluginException("Could not locate video file (source) at location "
+                                       + job.getActualVideoDestination().getAbsolutePath());
+               }
+               
+               String limitStr = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VCF_PER_JOB_LIMIT);
+               int vcfCounter;
+               try {
+                       vcfCounter = Integer.valueOf(limitStr);
+               } catch (NumberFormatException e) {
+                       throw new EncoderPluginException("Invalid value \"" + limitStr + "\" for setting " + Preferences.VCF_PER_JOB_LIMIT);
+               }
+               
+               //check vdub.exe
+               String vDubBinary = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VIRTUAL_DUB_BINARY_PATH);
+               File vDubBinaryFile = new File(vDubBinary);
+               if (!vDubBinaryFile.exists() || !vDubBinaryFile.canExecute()) {
+                       throw new EncoderPluginException("Invalid location for the vdub.exe: " + vDubBinary);
+               }
+               
+               this.doEncoding(job, vcfCounter);
+       }
+
+       @Override
+       public Properties getGlobalPreferences() {
+               return this.globalDefaultPreferences;
+       }
+
+       @Override
+       public String[] getGlobalPreferencesOrder() {
+               return Preferences.GLOBAL_PREFERENCES_ORDER;
+       }
+
+       @Override
+       public Properties getJobSpecificPreferences() {
+               this.checkAppLayer();
+               Properties jobSpecificPreferences = new Properties();
+               
+               //static properties
+               jobSpecificPreferences.setProperty(Preferences.CLEAR_JOBCONTROL, "true");
+               jobSpecificPreferences.setProperty(Preferences.RENDER_OUTPUT, "true");
+               
+               //dynamic properties
+               String limitStr = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VCF_PER_JOB_LIMIT);
+               try {
+                       int limit = Integer.valueOf(limitStr);
+                       if (limit > 0) {
+                               for (int i = 1; i <= limit; i++) {
+                                       jobSpecificPreferences.setProperty(Preferences.VCF_PATH + i, "filechooser");
+                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.OUTPUT_FILE_MODE))) {
+                                               //filechooser
+                                               jobSpecificPreferences.setProperty(Preferences.OUTPUT_FILE + i, "filechooser");
+                                       } else {
+                                               //suffix
+                                               jobSpecificPreferences.setProperty(Preferences.OUTPUT_SUFFIX + i, "_vdub" + i);
+                                       }
+                                       
+                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.EXTRA_OPTIONS))) {
+                                               String useEncStringKey = Preferences.USE_ENCODED_VIDEO + i + Preferences.USE_ENCODED_VIDEO_2;
+                                               jobSpecificPreferences.setProperty(useEncStringKey, "false");
+                                               jobSpecificPreferences.setProperty(Preferences.DELETE_ORIG_FILE + i, "false");
+                                       }
+                               }
+                       }
+               } catch (NumberFormatException e) {
+                       throw new DemoRecorderException("Invalid value \"" + limitStr + "\" for setting " + Preferences.VCF_PER_JOB_LIMIT);
+               }
+               
+               return jobSpecificPreferences;
+       }
+       
+       @Override
+       public String[] getJobSpecificPreferencesOrder() {
+               this.checkAppLayer();
+               List<String> preferencesOrderList = new ArrayList<String>();
+               
+               //static properties
+               preferencesOrderList.add(Preferences.CLEAR_JOBCONTROL);
+               preferencesOrderList.add(Preferences.RENDER_OUTPUT);
+               
+               //dynamic properties
+               String limitStr = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VCF_PER_JOB_LIMIT);
+               try {
+                       int limit = Integer.valueOf(limitStr);
+                       if (limit > 0) {
+                               for (int i = 1; i <= limit; i++) {
+                                       preferencesOrderList.add(Preferences.VCF_PATH + i);
+                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.OUTPUT_FILE_MODE))) {
+                                               //filechooser
+                                               preferencesOrderList.add(Preferences.OUTPUT_FILE + i);
+                                       } else {
+                                               //suffix
+                                               preferencesOrderList.add(Preferences.OUTPUT_SUFFIX + i);
+                                       }
+                                       
+                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.EXTRA_OPTIONS))) {
+                                               String useEncStringKey = Preferences.USE_ENCODED_VIDEO + i + Preferences.USE_ENCODED_VIDEO_2;
+                                               preferencesOrderList.add(useEncStringKey);
+                                               preferencesOrderList.add(Preferences.DELETE_ORIG_FILE + i);
+                                       }
+                               }
+                       }
+               } catch (NumberFormatException e) {
+                       throw new DemoRecorderException("Invalid value \"" + limitStr + "\" for setting " + Preferences.VCF_PER_JOB_LIMIT);
+               }
+               
+               Object[] arr = preferencesOrderList.toArray();
+               String[] stringArr = new String[arr.length];
+               for (int i = 0; i < arr.length; i++) {
+                       stringArr[i] = (String) arr[i];
+               }
+               
+               return stringArr;
+       }
+
+       @Override
+       public String getName() {
+               return PLUGIN_NAME;
+       }
+
+       @Override
+       public boolean isEnabled() {
+               this.checkAppLayer();
+               String enabledString = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.ENABLED);
+               return Boolean.valueOf(enabledString);
+       }
+
+       @Override
+       public void setApplicationLayer(DemoRecorderApplication appLayer) {
+               this.appLayer = appLayer;
+       }
+       
+       private void checkAppLayer() {
+               if (this.appLayer == null) {
+                       throw new DemoRecorderException("Error in plugin " + PLUGIN_NAME + "! Application layer not set!");
+               }
+       }
+       
+       private void createPreferenceDefaultValues() {
+               this.globalDefaultPreferences.setProperty(Preferences.ENABLED, "false");
+               this.globalDefaultPreferences.setProperty(Preferences.VIRTUAL_DUB_BINARY_PATH, "filechooser");
+               this.globalDefaultPreferences.setProperty(Preferences.VCF_PER_JOB_LIMIT, "1");
+               this.globalDefaultPreferences.setProperty(Preferences.OUTPUT_FILE_MODE, "false");
+               this.globalDefaultPreferences.setProperty(Preferences.EXTRA_OPTIONS, "false");
+       }
+       
+       private void doEncoding(RecordJob job, int vcfCounter) throws EncoderPluginException {
+               boolean firstValidVCF = true;
+               for (int i = 1; i <= vcfCounter; i++) {
+                       Properties jobSpecificSettings = job.getEncoderPluginSettings(this);
+                       String path = jobSpecificSettings.getProperty(Preferences.VCF_PATH + i);
+                       if (path != null) {
+                               File vcfFile = new File(path);
+                               if (vcfFile.exists()) {
+                                       if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.OUTPUT_FILE_MODE))) {
+                                               //filechooser
+                                               String outputPath = jobSpecificSettings.getProperty(Preferences.OUTPUT_FILE + i, "filechooser");
+                                               if (outputPath == null || outputPath.equals("") || outputPath.equals("filechoose")) {
+                                                       //user has not yet selected a file
+                                                       continue;
+                                               }
+                                       } else {
+                                               //suffix
+                                               String suffix = jobSpecificSettings.getProperty(Preferences.OUTPUT_SUFFIX + i);
+                                               if (suffix == null || suffix.equals("")) {
+                                                       continue;
+                                               }
+                                       }
+                                       BufferedWriter logWriter = this.getLogWriter(job.getJobName(), i);
+                                       this.executeVDub(job, i, firstValidVCF, logWriter);
+                                       firstValidVCF = false;
+                               }
+                       }
+               }
+       }
+       
+       private void executeVDub(RecordJob job, int index, boolean firstValidVCF, BufferedWriter logWriter) throws EncoderPluginException {
+               String shellString = "";
+               Properties jobSpecificSettings = job.getEncoderPluginSettings(this);
+               File vcfFile = new File(jobSpecificSettings.getProperty(Preferences.VCF_PATH + index));
+               File sourceFile = job.getActualVideoDestination();
+               
+               String vDubBinary = this.appLayer.getPreferences().getProperty(this.getName(), Preferences.VIRTUAL_DUB_BINARY_PATH);
+               shellString += '"' + vDubBinary.trim() + '"';
+               
+               shellString += " /s " + '"' + vcfFile.getAbsolutePath() + '"';
+               
+               boolean clearJobControl = Boolean.valueOf(jobSpecificSettings.getProperty(Preferences.CLEAR_JOBCONTROL, "true"));
+               if (clearJobControl && firstValidVCF) {
+                       shellString += " /c";
+               }
+               
+               String outputFilePath = this.getOutputFilePath(job, index);
+               File outputFile = new File(outputFilePath);
+               shellString += " /p " + '"' + sourceFile.getAbsolutePath() + '"';
+               shellString += " " + '"' + outputFilePath + '"';
+               
+               boolean renderOutput = Boolean.valueOf(jobSpecificSettings.getProperty(Preferences.RENDER_OUTPUT, "true"));
+               if (renderOutput) {
+                       shellString += " /r";
+               }
+               
+               shellString += " /x";
+               
+               try {
+                       logWriter.write("Executing commandline: " + shellString);
+                       logWriter.newLine();
+                       File vdubDir = new File(vDubBinary).getParentFile();
+                       Process vDubProc;
+                       vDubProc = Runtime.getRuntime().exec(shellString, null, vdubDir);
+                       vDubProc.getOutputStream();
+                       InputStreamReader isr = new InputStreamReader(vDubProc.getInputStream());
+                       BufferedReader bufferedInputStream = new BufferedReader(isr);
+                       String currentLine;
+                       while ((currentLine = bufferedInputStream.readLine()) != null) {
+                               logWriter.write(currentLine);
+                               logWriter.newLine();
+                       }
+                       InputStreamReader isrErr = new InputStreamReader(vDubProc.getErrorStream());
+                       BufferedReader bufferedInputStreamErr = new BufferedReader(isrErr);
+                       while ((currentLine = bufferedInputStreamErr.readLine()) != null) {
+                               logWriter.write(currentLine);
+                               logWriter.newLine();
+                       }
+                       logWriter.close();
+                       
+               } catch (IOException e) {
+                       throw new EncoderPluginException("I/O Exception occurred when trying to execute the VDub binary or logging output", e);
+               }
+               
+               //extra options: replace original video with encoded one, possibly delete original one
+               if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.EXTRA_OPTIONS))) {
+                       String useEncStringKey = Preferences.USE_ENCODED_VIDEO + index + Preferences.USE_ENCODED_VIDEO_2;
+                       String useEncVideo = jobSpecificSettings.getProperty(useEncStringKey);
+                       File origFile = job.getActualVideoDestination();
+                       if (useEncVideo != null && Boolean.valueOf(useEncVideo)) {
+                               job.setActualVideoDestination(outputFile);
+                       }
+                       
+                       String deleteOrigFile = jobSpecificSettings.getProperty(Preferences.DELETE_ORIG_FILE + index);
+                       if (deleteOrigFile != null && Boolean.valueOf(deleteOrigFile)) {
+                               //only delete the original file if the encoded one exists:
+                               if (outputFile.exists() && outputFile.length() > 0) {
+                                       origFile.delete();
+                               }
+                       }
+               }
+       }
+       
+       private String getOutputFilePath(RecordJob job, int index) {
+               File sourceFile = job.getActualVideoDestination();
+               String ext = DemoRecorderUtils.getFileExtension(sourceFile);
+               String outputFilePath;
+               Properties jobSpecificSettings = job.getEncoderPluginSettings(this);
+               if (Boolean.valueOf(this.appLayer.getPreferences().getProperty(this.getName(), Preferences.OUTPUT_FILE_MODE))) {
+                       //filechooser
+                       outputFilePath = jobSpecificSettings.getProperty(Preferences.OUTPUT_FILE + index);
+               } else {
+                       //suffix
+                       outputFilePath = sourceFile.getAbsolutePath();
+                       String suffix = jobSpecificSettings.getProperty(Preferences.OUTPUT_SUFFIX + index);
+                       int idx = outputFilePath.indexOf("." + ext);
+                       outputFilePath = outputFilePath.substring(0, idx);
+                       outputFilePath += suffix + "." + ext;
+               }
+               
+               return outputFilePath;
+       }
+       
+       private BufferedWriter getLogWriter(String jobName, int vcfIndex) throws EncoderPluginException {
+               File logDir = DemoRecorderUtils.computeLocalFile(DemoRecorderApplication.LOGS_DIRNAME, "");
+               if (jobName == null || jobName.equals("")) {
+                       jobName = "unnamed_job";
+               }
+               String path = logDir.getAbsolutePath() + File.separator + PLUGIN_NAME + '_' + jobName + '_' + "vcf" + vcfIndex + ".log";
+               File logFile = new File(path);
+               if (!DemoRecorderUtils.attemptFileCreation(logFile)) {
+                       throw new EncoderPluginException("Could not create log file for VDub job at location: " + path);
+               }
+               try {
+                       FileWriter fileWriter = new FileWriter(logFile);
+                       return new BufferedWriter(fileWriter);
+               } catch (IOException e) {
+                       throw new EncoderPluginException("Could not create log file for VDub job at location: " + path, e);
+               }
+       }
+}