/*! Copyright (C) 2009 Apertus, All Rights Reserved *! Author : Apertus Team *! Description: Mplayer class taking care of anything related to mplayer -----------------------------------------------------------------------------** *! *! 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, either version 3 of the License, or *! (at your option) any later version. *! *! 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, see <http://www.gnu.org/licenses/>. *! -----------------------------------------------------------------------------**/ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.io.PrintStream; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JTextArea; // List of available commands: http://www1.mplayerhq.hu/DOCS/tech/slave.txt public class Mplayer { static boolean debug = false; private ElphelVision Parent; private Process mplayerProcess; private PrintStream mplayerIn; private BufferedReader mplayerOutErr; private static Logger logger = Logger.getLogger(ElphelVision.class.getName()); private JTextArea debugout; Mplayer(ElphelVision parent) { this.Parent = parent; } public void open(String file, String parameters, String mplayerpath) throws IOException { if (mplayerProcess == null) { String command = mplayerpath + " " + parameters + " " + file; Parent.WriteLogtoConsole("Starting MPlayer process: " + command); mplayerProcess = Runtime.getRuntime().exec(command); // create the piped streams where to redirect the standard output and error of MPlayer // specify a bigger pipesize PipedInputStream readFrom = new PipedInputStream(1024 * 1024); PipedOutputStream writeTo = new PipedOutputStream(readFrom); mplayerOutErr = new BufferedReader(new InputStreamReader(readFrom)); // create the threads to redirect the standard output and error of MPlayer new LineRedirecter(debugout, mplayerProcess.getInputStream(), writeTo, "MPlayer says: ").start(); new LineRedirecter(debugout, mplayerProcess.getErrorStream(), writeTo, "MPlayer encountered an error: ").start(); // the standard input of MPlayer mplayerIn = new PrintStream(mplayerProcess.getOutputStream()); } else { execute("loadfile \"" + file + "\" 0"); } // wait to start playing waitForAnswer("Starting playback..."); Parent.WriteLogtoConsole("Started playing: " + file); } public void close() { if (mplayerProcess != null) { execute("quit"); try { mplayerProcess.waitFor(); } catch (InterruptedException e) { } mplayerProcess = null; } } public File getPlayingFile() { String path = getProperty("path"); return path == null ? null : new File(path); } public void togglePlay() { execute("pause"); } public boolean isPlaying() { return mplayerProcess != null; } public long getTimePosition() { return getPropertyAsLong("time_pos"); } public void setTimePosition(long seconds) { setProperty("time_pos", seconds); } public long getTotalTime() { return getPropertyAsLong("length"); } public float getVolume() { return getPropertyAsFloat("volume"); } public void setVolume(float volume) { setProperty("volume", volume); } protected String getProperty(String name) { if (name == null || mplayerProcess == null) { return null; } String s = "ANS_" + name + "="; String x = execute("get_property " + name, s); if (x == null) { return null; } if (!x.startsWith(s)) { return null; } return x.substring(s.length()); } protected long getPropertyAsLong(String name) { try { return Long.parseLong(getProperty(name)); } catch (NumberFormatException exc) { } catch (NullPointerException exc) { } return 0; } protected float getPropertyAsFloat(String name) { try { return Float.parseFloat(getProperty(name)); } catch (NumberFormatException exc) { } catch (NullPointerException exc) { } return 0f; } protected void setProperty(String name, String value) { execute("set_property " + name + " " + value); } protected void setProperty(String name, long value) { execute("set_property " + name + " " + value); } protected void setProperty(String name, float value) { execute("set_property " + name + " " + value); } protected void ExecuteCommand(String command) { execute(command, null); } /** Sends a command to MPlayer.. * @param command the command to be sent */ private void execute(String command) { execute(command, null); } /** Sends a command to MPlayer and waits for an answer. * @param command the command to be sent * @param expected the string with which has to start the line; if null don't wait for an answer * @return the MPlayer answer */ private String execute(String command, String expected) { if (mplayerProcess != null) { logger.info("Send to MPlayer the command \"" + command + "\" and expecting " + (expected != null ? "\"" + expected + "\"" : "no answer")); mplayerIn.print(command); mplayerIn.print("\n"); mplayerIn.flush(); //logger.info("Command sent"); if (expected != null) { String response = waitForAnswer(expected); logger.info("MPlayer command response: " + response); return response; } } return null; } /** Read from the MPlayer standard output and error a line that starts with the given parameter and return it. * @param expected the expected starting string for the line * @return the entire line from the standard output or error of MPlayer */ private String waitForAnswer(String expected) { // todo add the possibility to specify more options to be specified // todo use regexp matching instead of the beginning of a string String line = null; if (expected != null) { try { while ((line = mplayerOutErr.readLine()) != null) { logger.info("Reading line: " + line); if (line.startsWith(expected)) { //debugoutput.append(line); return line; } } } catch (IOException e) { } } return line; } /** A thread that reads from an input stream and outputs to another line by line. */ private static class LineRedirecter extends Thread { /** The input stream to read from. */ private InputStream in; /** The output stream to write to. */ private OutputStream out; /** The prefix used to prefix the lines when outputting to the logger. */ private String prefix; private JTextArea debugoutput; /** * @param in the input stream to read from. * @param out the output stream to write to. * @param prefix the prefix used to prefix the lines when outputting to the logger. */ LineRedirecter(JTextArea debugout, InputStream in, OutputStream out, String prefix) { this.in = in; this.out = out; this.prefix = prefix; //this.debugoutput = debugout; } public void run() { try { // creates the decorating reader and writer BufferedReader reader = new BufferedReader(new InputStreamReader(in)); PrintStream printStream = new PrintStream(out); String line; // read line by line while ((line = reader.readLine()) != null) { //logger.info((prefix != null ? prefix : "") + line); printStream.println(line); //this.debugoutput.append(line + "\n"); } } catch (IOException exc) { logger.log(Level.WARNING, "An error has occured while grabbing lines", exc); } } } }