/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package webcamstudio.externals; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.lang.reflect.Field; import java.net.MalformedURLException; import java.net.SocketException; import java.net.URL; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import static webcamstudio.WebcamStudio.audioFreq; import static webcamstudio.WebcamStudio.outFMEbe; import static webcamstudio.WebcamStudio.wsDistroWatch; import static webcamstudio.externals.ProcessRenderer.ACTION.OUTPUT; import webcamstudio.media.renderer.Capturer; import webcamstudio.media.renderer.Exporter; import webcamstudio.media.renderer.ProcessExecutor; import webcamstudio.mixers.Frame; import webcamstudio.mixers.MasterMixer; import webcamstudio.streams.SinkFile; import webcamstudio.streams.SinkUDP; import webcamstudio.streams.SourceDVB; import webcamstudio.streams.Stream; import webcamstudio.util.Tools; import webcamstudio.util.Tools.OS; /** * * @author patrick (modified by karl) * * ProcessRenderer is used to execute external commands which produce * audio or video streams, and to manage the process of reading those * streams. * * ProcessRenderer first tries to load a .properties file defining the * command to be run. This will either be a file in the application * JAR selected by the caller's choice of plugin, or a user * .properties file in ~/.webcamstudio * * Next ProcessRenderer replaces parameter markers in the command * string with parameter values obtained from the associated Stream * * Finally, ProcessRenderer launches the command process, and (in the * case of sources) launches a Capturer to read the data from the * process output. */ public class ProcessRenderer { final static String RES_CAP = "capture_OS.properties"; final static String RES_OUT = "output_OS.properties"; private final static String userHomeDir = Tools.getUserHome(); public static String pidOutput; //Author Martijn Courteaux Code public static int getUnixPID(Process process) throws Exception { System.out.println("Process_GetUnixPid: "+process.getClass().getName()); if (process.getClass().getName().equals("java.lang.UNIXProcess")) { Class cl = process.getClass(); Field field = cl.getDeclaredField("pid"); field.setAccessible(true); Object pidObject = field.get(process); return (Integer) pidObject; } else { throw new IllegalArgumentException("Needs to be a UNIXProcess"); } } java.io.DataInput input = null; boolean stopMe = false; boolean stopped = true; private Properties plugins = null; String plugin = ""; // Used to select the .properties file containing command strings String oPlug = "output"; String audioPulseInput = ""; int videoPort = 0; int audioPort = 0; int frequency = audioFreq; int channels = 2; int bitSize = 16; Stream stream; ProcessExecutor processVideo; ProcessExecutor processAudio; Capturer capture; Exporter exporter; FME fme = null; private final MasterMixer mixer = MasterMixer.getInstance(); public ProcessRenderer(Stream s, ACTION action, String plugin, String bkEnd) { stream = s; // System.out.println("BackEnd:"+bkEnd); String distro = wsDistroWatch(); if (bkEnd.equals("FF")) { if (action == OUTPUT) { //System.out.println("Action Output - BackEnd FF !!!"); this.oPlug = "ffmpeg_output"; this.plugin = plugin; } else { this.oPlug = "output"; this.plugin = "ffmpeg_" + plugin; s.setComm("AV"); } } else { if (action == OUTPUT) { if (bkEnd.equals("AV")) { this.oPlug = "output"; this.plugin = plugin; } else { this.oPlug = "gst_output"; this.plugin = plugin; } } else { if (distro.toLowerCase().equals("ubuntu")) { this.plugin = plugin; } else if ("AV".equals(bkEnd) && plugin.equals("audiosource")) { this.plugin = "av_" + plugin; } else { //if ("AV".equals(bkEnd)) this.plugin = plugin; } } } // System.out.println("OPlugin:"+oPlug); // System.out.println("Plugin: "+this.plugin); if (plugins == null) { plugins = new Properties(); try { if (plugin.equals("custom")) { plugins.load(stream.getFile().toURI().toURL().openStream()); System.out.println("Plugins Custom: "+plugins); } else { plugins.load(getResource(action).openStream()); } } catch (IOException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } } processVideo = new ProcessExecutor(s.getName()); processAudio = new ProcessExecutor(s.getName()); } public ProcessRenderer(Stream s, FME fme, String plugin) { stream = s; this.plugin = plugin; if (outFMEbe == 0) { this.oPlug = "ffmpeg_output"; } else if (outFMEbe == 1) { this.oPlug = "output"; } else if (outFMEbe == 2) { this.oPlug = "gst_output"; } this.fme = fme; if (plugins == null) { plugins = new Properties(); try { plugins.load(getResource(ACTION.OUTPUT).openStream()); } catch (IOException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } } processVideo = new ProcessExecutor(s.getName()); processAudio = new ProcessExecutor(s.getName()); } private String translateTag(String value) { String result = value.toUpperCase().replace('.', '_'); if (plugins.containsKey("TAG_" + result)) { result = plugins.getProperty("TAG_" + result); } return result; } private URL getResource(ACTION a) throws MalformedURLException { File userSettings = null; switch (a) { case CAPTURE: userSettings = new File(new File(userHomeDir + "/.webcamstudio"), RES_CAP.replaceAll("OS", Tools.getOSName())); break; case OUTPUT: userSettings = new File(new File(userHomeDir + "/.webcamstudio"), RES_OUT.replaceAll("OS", Tools.getOSName())); break; } URL res = null; // FIXME: It seems what we've provided here is a way for the // user to override all the supplied source properties files // with ONE file: // So if I create // ~/.webcamstudio/capture_linux.properties and run WCS, // any source I try to launch will use the settings from that // file and there will be no difference between the different // types of sources... right? ---GEC if (userSettings.exists()) { res = userSettings.toURI().toURL(); } else { String path = null; switch (a) { case CAPTURE: path = "/webcamstudio/externals/OS/sources/" + plugin + ".properties"; path = path.replaceAll("OS", Tools.getOSName()); break; case OUTPUT: path = "/webcamstudio/externals/OS/outputs/"+ oPlug +".properties"; path = path.replaceAll("OS", Tools.getOSName()); break; } // Pull back-end properties file from JAR or installation directory res = ProcessRenderer.class.getResource(path); } // System.out.println("Resource Used: " + res.toString()); return res; } private String setParameters(String cmd) { String command = cmd; String fmeName = null; String fmeURL = null; if (fme != null) { fmeName = fme.getName(); fmeURL = fme.getUrl(); } /* TODO: Replace this with a more elegant system. For instance: 1: Add to Stream a call which provides all the tags and associated command string text for the stream 2: Merge the data obtained in a call to (1) with a set of command parameters defined here (such as videoPort, etc.) 3: Loop through the constructed list of parameters to perform the substitutions As a result ProcessRenderer will no longer need to switch through an exhaustive list of parameters supported by different Streams ---GEC */ for (Tags tag : Tags.values()) { switch (tag) { case DESKTOPN: command = command.replaceAll(Tags.DESKTOPN.toString(), stream.getDesktopN() + ""); break; case DESKTOPX: command = command.replaceAll(Tags.DESKTOPX.toString(), stream.getDesktopX() + ""); break; case DESKTOPY: command = command.replaceAll(Tags.DESKTOPY.toString(), stream.getDesktopY() + ""); break; case DESKTOPENDX: command = command.replaceAll(Tags.DESKTOPENDX.toString(), stream.getDesktopEndX() + ""); break; case DESKTOPENDY: command = command.replaceAll(Tags.DESKTOPENDY.toString(), stream.getDesktopEndY() + ""); break; case DESKTOPW: command = command.replaceAll(Tags.DESKTOPW.toString(), stream.getDesktopW() + ""); break; case DESKTOPH: command = command.replaceAll(Tags.DESKTOPH.toString(), stream.getDesktopH() + ""); break; case XID: command = command.replaceAll(Tags.XID.toString(), stream.getDesktopXid() + ""); break; case WINDOWX: command = command.replaceAll(Tags.WINDOWX.toString(), stream.getWindowX() + ""); break; case WINDOWY: command = command.replaceAll(Tags.WINDOWY.toString(), stream.getWindowY() + ""); break; case WINDOWENDX: command = command.replaceAll(Tags.WINDOWENDX.toString(), stream.getWindowEndX() + ""); break; case WINDOWENDY: command = command.replaceAll(Tags.WINDOWENDY.toString(), stream.getWindowEndY() + ""); break; case GUID: command = command.replaceAll(Tags.GUID.toString(), stream.getGuid() + ""); break; case VCODEC: if (fme != null) { command = command.replaceAll(Tags.VCODEC.toString(), translateTag(fme.getVcodec())); } break; case ACODEC: if (fme != null) { command = command.replaceAll(Tags.ACODEC.toString(), translateTag(fme.getAcodec())); } break; case VBITRATE: if (fme != null) { command = command.replaceAll(Tags.VBITRATE.toString(), fme.getVbitrate()); } if (stream instanceof SinkFile || stream instanceof SinkUDP) { command = command.replaceAll(Tags.VBITRATE.toString(), stream.getVbitrate()); } break; case ABITRATE: if (fme != null) { command = command.replaceAll(Tags.ABITRATE.toString(), fme.getAbitrate()); } if (stream instanceof SinkFile || stream instanceof SinkUDP) { command = command.replaceAll(Tags.ABITRATE.toString(), stream.getAbitrate()); } break; case URL: if (fme != null) { if (!"".equals(fme.getMount())) { command = command.replaceAll(Tags.URL.toString(), "" + fmeURL); } else { command = command.replaceAll(Tags.URL.toString(), "" + fmeURL + "/" + fme.getStream()); // "\""+fme.getUrl()+"/"+fme.getStream()+" live=1 flashver=FME/2.520(compatible;20FMSc201.0)"+"\"" } } else if (stream.getURL() != null) { command = command.replaceAll(Tags.URL.toString(), "" + stream.getURL()); } break; case MOUNT: if (fme != null && !"".equals(fme.getMount())) { command = command.replaceAll(Tags.MOUNT.toString(), "" + fme.getMount()); } break; case PASSWORD: if (fme != null && !"".equals(fme.getPassword())) { command = command.replaceAll(Tags.PASSWORD.toString(), "" + fme.getPassword()); } break; case KEYINT: if (fme != null) { command = command.replaceAll(Tags.KEYINT.toString(), "" + fme.getKeyInt()); } else { command = command.replaceAll(Tags.KEYINT.toString(), "" + Integer.toString(5*mixer.getRate())); } break; case PORT: if (fme != null && !"".equals(fme.getPort())) { command = command.replaceAll(Tags.PORT.toString(), "" + fme.getPort()); } break; case APORT: command = command.replaceAll(Tags.APORT.toString(), "" + audioPort); break; case CHEIGHT: command = command.replaceAll(Tags.CHEIGHT.toString(), "" + stream.getCaptureHeight()); break; case CWIDTH: command = command.replaceAll(Tags.CWIDTH.toString(), "" + stream.getCaptureWidth()); break; case FILE: if (stream.getFile() != null) { if (Tools.getOS() == OS.WINDOWS) { command = command.replaceAll(Tags.FILE.toString(), "\"" + stream.getFile().getAbsolutePath().replaceAll("\\\\", "\\\\\\\\") + "\""); } else { if (stream.getFile().getAbsolutePath().contains("http")) { command = command.replaceAll(Tags.FILE.toString(), "" + stream.getFile().getAbsolutePath().replace(userHomeDir+"/", "") + ""); } else { String sFile = stream.getFile().getAbsolutePath().replaceAll(" ", "\\ "); if (stream instanceof SinkFile) { sFile = sFile.replaceAll(" ", "_"); } command = command.replaceAll(Tags.FILE.toString(), "" + sFile + ""); } } } break; case OHEIGHT: command = command.replaceAll(Tags.OHEIGHT.toString(), "" + stream.getHeight()); break; case OWIDTH: command = command.replaceAll(Tags.OWIDTH.toString(), "" + stream.getWidth()); break; case RATE: command = command.replaceAll(Tags.RATE.toString(), "" + stream.getRate()); break; case SEEK: command = command.replaceAll(Tags.SEEK.toString(), "" + stream.getSeek()); break; case VPORT: command = command.replaceAll(Tags.VPORT.toString(), "" + videoPort); break; case GSEFFECT: command = command.replaceAll(Tags.GSEFFECT.toString(), "" + stream.getGSEffect()); break; case WEBURL: if (stream.getProtected() && "wanscam".equals(stream.getPtzBrand())) { String soloURL = stream.getWebURL().replace("http://", ""); command = command.replaceAll(Tags.WEBURL.toString(), "\""+"http://"+soloURL+"?user="+stream.getIPUser()+"&pwd="+stream.getIPPwd()+"\""); } if (stream.getProtected()) { String soloURL = stream.getWebURL().replace("http://", ""); command = command.replaceAll(Tags.WEBURL.toString(), "\""+"http://"+stream.getIPUser()+":"+stream.getIPPwd()+"@"+soloURL+"\""); } else { command = command.replaceAll(Tags.WEBURL.toString(), "\""+stream.getWebURL()+"\""); } break; case BW: command = command.replaceAll(Tags.BW.toString(), "" + stream.getDVBBandwidth()); break; case DVBFREQ: command = command.replaceAll(Tags.DVBFREQ.toString(), "" + stream.getDVBFrequency()); break; case DVBCH: command = command.replaceAll(Tags.DVBCH.toString(), "" + stream.getDVBChannelNumber()); break; case FREQ: command = command.replaceAll(Tags.FREQ.toString(), "" + frequency); break; case BITSIZE: command = command.replaceAll(Tags.BITSIZE.toString(), "" + bitSize); break; case CHANNELS: command = command.replaceAll(Tags.CHANNELS.toString(), "" + channels); break; case AUDIOSRC: command = command.replaceAll(Tags.AUDIOSRC.toString(), "" + stream.getAudioSource()); break; case PAUDIOSRC: command = command.replaceAll(Tags.PAUDIOSRC.toString(), "" + audioPulseInput); break; } } return command; } public Frame getFrame() { if (capture == null) { return null; } else { return capture.getFrame(); } } public void read() { stopped = false; stopMe = false; new Thread(new Runnable() { @Override public void run() { capture = new Capturer(stream); String cmdVideo = ""; String cmdAudio = ""; if (stream.hasVideo()) { videoPort = capture.getVideoPort(); } if (stream.hasAudio()) { audioPort = capture.getAudioPort(); } String commandVideo = null; String commandAudio = null; // System.out.println(plugins.keySet().toString()); if (stream.hasVideo()) { if ("AV".equals(stream.getComm())) { commandVideo = plugins.getProperty("AVvideo").replaceAll(" ", " "); //Making sure there is no double spaces } else { if (!"".equals(stream.getGSEffect())) { if (!"".equals(stream.getDesktopXid())) { commandVideo = plugins.getProperty("GSvideoFXSingle").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandVideo = plugins.getProperty("GSvideoFX").replaceAll(" ", " "); //Making sure there is no double spaces } } else { if (!"".equals(stream.getDesktopXid())) { commandVideo = plugins.getProperty("GSvideoSingle").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandVideo = plugins.getProperty("GSvideo").replaceAll(" ", " "); //Making sure there is no double spaces } } } } if (stream.hasAudio()) { if ("AV".equals(stream.getComm())) { commandAudio = plugins.getProperty("AVaudio").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandAudio = plugins.getProperty("GSaudio").replaceAll(" ", " "); //Making sure there is no double spaces } } // fix gst-launch dvbsrc >= 1.4 "delsys" issue. if (stream instanceof SourceDVB) { try { Runtime.getRuntime().exec("gst-launch-1.0 -q dvbsrc delsys=DVB-T2"); } catch (IOException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } Tools.sleep(100); } if (commandVideo != null) { // FIXME: This "ABCDE" business is kind of crap, // and using String.split() to split arguments means we have no way to put a space in a command argument. ---GEC commandVideo = commandVideo.replaceAll(" ", "ABCDE"); commandVideo = setParameters(commandVideo); String[] parmsVideo = commandVideo.split("ABCDE"); try { for (String p : parmsVideo) { cmdVideo = cmdVideo + p + " "; } System.out.print("CommandVideo: "+cmdVideo+"\n"); processVideo.execute(parmsVideo); } catch (IOException | InterruptedException e) { Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, e); } } else { processVideo = null; } if (commandAudio != null) { commandAudio = commandAudio.replaceAll(" ", "ABCDE"); commandAudio = setParameters(commandAudio); String[] parmsAudio = commandAudio.split("ABCDE"); try { for (String p : parmsAudio) { cmdAudio = cmdAudio + p + " "; } System.out.print("CommandAudio: "+cmdAudio+"\n"); processAudio.execute(parmsAudio); } catch (IOException | InterruptedException e) { Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, e); } } else { processAudio = null; } } }).start(); } public void readCom() { stopped = false; stopMe = false; final String iD = stream.getID().substring(0, 4); new Thread(new Runnable() { @Override public void run() { if (stream.isIPCam()) { stream.setVideo(true); } capture = new Capturer(stream); if (stream.isOnlyAudio()) { processVideo = null; } else { videoPort = capture.getVideoPort(); } if (stream.hasAudio()) { audioPort = capture.getAudioPort(); } else { processAudio = null; } String commandVideo = null; String commandAudio = null; if (stream.hasVideo() && stream.isIPCam()) { commandVideo = plugins.getProperty("videoIP").replaceAll(" ", " "); //Making sure there is no double spaces } else if (stream.hasVideo() && stream.isStillPicture()) { commandVideo = plugins.getProperty("videoPic").replaceAll(" ", " "); //Making sure there is no double spaces } else if (stream.hasVideo() && stream.isRTSP()) { if (stream.getComm().equals("GS")) { if (!"".equals(stream.getGSEffect())) { commandVideo = plugins.getProperty("RTSPvideoFX").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandVideo = plugins.getProperty("GSRTSPvideo").replaceAll(" ", " "); //Making sure there is no double spaces } } else { commandVideo = plugins.getProperty("AVRTSPvideo").replaceAll(" ", " "); } } else if (stream.hasVideo() && stream.isRTMP()) { if (stream.getComm().equals("GS")) { if (!"".equals(stream.getGSEffect())) { commandVideo = plugins.getProperty("RTMPvideoFX").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandVideo = plugins.getProperty("GSRTMPvideo").replaceAll(" ", " "); //Making sure there is no double spaces } } else { commandVideo = plugins.getProperty("AVRTMPvideo").replaceAll(" ", " "); } } else if (stream.hasVideo()) { if (stream.getWebURL().toLowerCase().startsWith("udp")) { if (!"".equals(stream.getGSEffect())) { commandVideo = plugins.getProperty("GSvideoUDPFX").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandVideo = plugins.getProperty("GSvideoUDP").replaceAll(" ", " "); //Making sure there is no double spaces } } else { if ("AV".equals(stream.getComm())) { if (!stream.isOnlyAudio()) { if (stream.hasVideo()) { commandVideo = plugins.getProperty("AVvideo").replaceAll(" ", " "); //Making sure there is no double spaces } else { if (!"".equals(stream.getGSEffect())) { commandVideo = plugins.getProperty("SndvideoFX").replaceAll(" ", " "); //Making sure there is no double spaces stream.setHasVideo(true); } else { commandVideo = plugins.getProperty("Sndvideo").replaceAll(" ", " "); //Making sure there is no double spaces stream.setHasVideo(true); } } } else { commandVideo = plugins.getProperty("AVvideo").replaceAll(" ", " "); //Making sure there is no double spaces } } else { if (!stream.isOnlyAudio()) { if (stream.hasVideo()) { if (!"".equals(stream.getGSEffect())) { commandVideo = plugins.getProperty("GSvideoFX").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandVideo = plugins.getProperty("GSvideo").replaceAll(" ", " "); //Making sure there is no double spaces } } else { if (!"".equals(stream.getGSEffect())) { commandVideo = plugins.getProperty("SndvideoFX").replaceAll(" ", " "); //Making sure there is no double spaces stream.setHasVideo(true); } else { commandVideo = plugins.getProperty("Sndvideo").replaceAll(" ", " "); //Making sure there is no double spaces stream.setHasVideo(true); } } } else { if (!"".equals(stream.getGSEffect())) { commandVideo = plugins.getProperty("GSvideoFX").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandVideo = plugins.getProperty("GSvideo").replaceAll(" ", " "); //Making sure there is no double spaces } } } } } if (stream.hasAudio()) { if (stream.getWebURL().toLowerCase().startsWith("udp")) { commandAudio = plugins.getProperty("GSaudioUDP").replaceAll(" ", " "); //Making sure there is no double spaces } else if (stream.isRTSP()) { if (stream.getComm().equals("GS")) { commandAudio = plugins.getProperty("GSRTSPaudio").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandAudio = plugins.getProperty("AVRTSPaudio").replaceAll(" ", " "); } } else if (stream.isRTMP()) { if (stream.getComm().equals("GS")) { commandAudio = plugins.getProperty("GSRTMPaudio").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandAudio = plugins.getProperty("AVRTMPaudio").replaceAll(" ", " "); } } else { if ("AV".equals(stream.getComm())) { commandAudio = plugins.getProperty("AVaudio").replaceAll(" ", " "); //Making sure there is no double spaces } else { commandAudio = plugins.getProperty("GSaudio").replaceAll(" ", " "); //Making sure there is no double spaces } } } if (commandVideo != null) { commandVideo = setParameters(commandVideo); } if (commandAudio != null) { commandAudio = setParameters(commandAudio); } System.out.println("CommandVideo: "+commandVideo); System.out.println("CommandAudio: "+commandAudio); File fileV=new File(userHomeDir + "/.webcamstudio/WSUVid" + iD + ".sh"); File fileA=new File(userHomeDir + "/.webcamstudio/WSUAud" + iD + ".sh"); FileOutputStream fosV; Writer dosV = null; FileOutputStream fosA; Writer dosA = null; try { fosV = new FileOutputStream(fileV); dosV = new OutputStreamWriter(fosV); fosA = new FileOutputStream(fileA); dosA = new OutputStreamWriter(fosA); } catch (FileNotFoundException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } try { dosV.write("#!/bin/bash\n"); dosV.write(commandVideo+"\n"); dosV.close(); dosA.write("#!/bin/bash\n"); dosA.write(commandAudio+"\n"); dosA.close(); } catch (IOException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } fileV.setExecutable(true); fileA.setExecutable(true); String batchVideoCommand = userHomeDir+"/.webcamstudio/WSUVid" + iD + ".sh"; String batchAudioCommand = userHomeDir+"/.webcamstudio/WSUAud" + iD + ".sh"; try { if (stream.hasVideo()) { processVideo.executeString(batchVideoCommand); } if (stream.hasAudio()) { processAudio.executeString(batchAudioCommand); } } catch (IOException | InterruptedException e) { Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, e); } } }).start(); } public void readCustom() { stopped = false; stopMe = false; final String iD = stream.getID().substring(0, 4); new Thread(new Runnable() { @Override public void run() { stream.setVideo(plugins.containsKey("video")); stream.setAudio(plugins.containsKey("audio")); stream.setFakeVideo(stream.hasVideo()); stream.setFakeAudio(stream.hasAudio()); // System.out.println("HasVideo: "+stream.hasVideo()); // System.out.println("HasFakeVideo: "+stream.hasFakeVideo()); capture = new Capturer(stream); if (stream.hasVideo()) { videoPort = capture.getVideoPort(); } if (stream.hasAudio()) { audioPort = capture.getAudioPort(); } String commandVideo = null; String commandAudio = null; if (stream.hasVideo()) { commandVideo = plugins.getProperty("video").replaceAll(" ", " "); //Making sure there is no double spaces } if (stream.hasAudio()) { commandAudio = plugins.getProperty("audio").replaceAll(" ", " "); //Making sure there is no double spaces } if (commandVideo != null) { commandVideo = setParameters(commandVideo); } if (commandAudio != null) { commandAudio = setParameters(commandAudio); } System.out.println("CommandVideo: "+commandVideo); System.out.println("CommandAudio: "+commandAudio); File fileV = new File(userHomeDir + "/.webcamstudio/WSCVid" + iD + ".sh"); File fileA = new File(userHomeDir + "/.webcamstudio/WSCAud" + iD + ".sh"); FileOutputStream fosV; Writer dosV = null; FileOutputStream fosA; Writer dosA = null; try { fosV = new FileOutputStream(fileV); dosV= new OutputStreamWriter(fosV); fosA = new FileOutputStream(fileA); dosA= new OutputStreamWriter(fosA); } catch (FileNotFoundException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } try { dosV.write("#!/bin/bash\n"); dosV.write(commandVideo+"\n"); dosV.close(); dosA.write("#!/bin/bash\n"); dosA.write(commandAudio+"\n"); dosA.close(); } catch (IOException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } fileV.setExecutable(true); fileA.setExecutable(true); String batchVideoCommand = userHomeDir+"/.webcamstudio/WSCVid" + iD + ".sh"; String batchAudioCommand = userHomeDir+"/.webcamstudio/WSCAud" + iD + ".sh"; try { if (stream.hasVideo()) { processVideo.executeString(batchVideoCommand); } else { processVideo = null; } if (stream.hasAudio()) { processAudio.executeString(batchAudioCommand); } else { processAudio = null; } } catch (IOException | InterruptedException e) { Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, e); } } }).start(); } public void writeCom() { stopped = false; stopMe = false; new Thread(new Runnable() { @Override public void run() { try { exporter = new Exporter(stream); } catch (SocketException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } stopped = false; stopMe = false; videoPort = exporter.getVideoPort(); audioPort = exporter.getAudioPort(); String command = plugins.getProperty(plugin).replaceAll(" ", " "); //Making sure there is no double spaces command = setParameters(command); System.out.println("Command Out: "+command); File file=new File(userHomeDir+"/.webcamstudio/"+"WSBro.sh"); FileOutputStream fos; Writer dos = null; try { fos = new FileOutputStream(file); dos= new OutputStreamWriter(fos); } catch (FileNotFoundException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } try { dos.write("#!/bin/bash\n"); dos.write(command+"\n"); dos.close(); } catch (IOException ex) { Logger.getLogger(ProcessRenderer.class.getName()).log(Level.SEVERE, null, ex); } file.setExecutable(true); String batchCommand = userHomeDir+"/.webcamstudio/"+"WSBro.sh"; try { if (stream.hasVideo()) { processAudio = null; processVideo.executeString(batchCommand); } else if (stream.hasAudio()) { processVideo = null; processAudio.executeString(batchCommand); } //We don't need processAudio on export. Only 1 process is required... } catch (IOException | InterruptedException e) { Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, e); } } }).start(); } public void pause() //Author Martijn Courteaux Code { if (processVideo != null) { capture.vPause(); } if (processAudio != null) { capture.aPause(); } } public void play() { if (processVideo != null) { capture.vPlay(); } if (processAudio != null) { capture.aPlay(); } } public void stop() { stopMe = true; stopped = true; if (capture != null) { capture.abort(); capture = null; // System.out.println(stream.getName()+" Capture Cleared ..."); } if (exporter != null) { exporter.abort(); exporter = null; // System.out.println(stream.getName()+" Export Cleared ..."); } if (processVideo != null) { processVideo.destroy(); processVideo = null; System.out.println(stream.getName()+" Video Cleared ..."); } if (processAudio != null) { processAudio.destroy(); processAudio = null; System.out.println(stream.getName()+" Audio Cleared ..."); } } public boolean isStopped() { return stopped; } public int getFrequency() { return frequency; } public int getBitSize() { return bitSize; } public int getChannels() { return channels; } public enum ACTION { CAPTURE, OUTPUT } }