/*
This file is part of JFLICKS.
JFLICKS 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.
JFLICKS 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 JFLICKS. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jflicks.player.mplayer;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.jflicks.job.AbstractJob;
import org.jflicks.job.JobContainer;
import org.jflicks.job.JobEvent;
import org.jflicks.job.JobListener;
import org.jflicks.job.JobManager;
import org.jflicks.job.SystemJob;
import org.jflicks.util.LogUtil;
import org.jflicks.util.Util;
/**
* This job starts a system job that runs mplayer. It also is a conduit to
* send mplayer commands over stdin.
*
* @author Doug Barnum
* @version 1.0
*/
public class MPlayerJob extends AbstractJob implements JobListener {
private MPlayer mplayer;
private SystemJob systemJob;
private JobContainer jobContainer;
private String windowId;
private long position;
private int seconds;
private String path;
private boolean autoSkip;
private FileWriter fileWriter;
private String[] args;
public MPlayerJob() {
}
/**
* Constructor with three required arguments. There are two ways to
* begin playing at some point in the video and if either is non-zero
* it will be used. The position field is checked first so it's best
* to have only one of them non-zero if playing past the beginning is
* desired.
*
* @param mplayer The player instance creating the job.
* @param wid A window ID.
* @param args An array of arguments to give to mplayer.
* @param position The number of bytes into the video to begin playing.
* @param seconds The number of seconds into the video to begin playing.
* @param path The path to the file to play.
* @param autoSkip When true try to auto skip commercials.
*/
public MPlayerJob(MPlayer mplayer, String wid, String[] args,
long position, int seconds, String path, boolean autoSkip) {
setMPlayer(mplayer);
setWindowId(wid);
setArgs(args);
setPosition(position);
setSeconds(seconds);
setPath(path);
setAutoSkip(autoSkip);
}
public MPlayer getMPlayer() {
return (mplayer);
}
public void setMPlayer(MPlayer p) {
mplayer = p;
}
public String[] getArgs() {
return (args);
}
public void setArgs(String[] array) {
args = array;
}
public SystemJob getSystemJob() {
return (systemJob);
}
public void setSystemJob(SystemJob j) {
systemJob = j;
}
public JobContainer getJobContainer() {
return (jobContainer);
}
public void setJobContainer(JobContainer j) {
jobContainer = j;
}
/**
* When set mplayer can be told to use an existing window instead of
* making a new one.
*
* @return A window ID as a String.
*/
public String getWindowId() {
return (windowId);
}
/**
* When set mplayer can be told to use an existing window instead of
* making a new one.
*
* @param s A window ID as a String.
*/
public void setWindowId(String s) {
windowId = s;
}
/**
* The video is going to begin at byte offset Position. Of course this
* could be zero signifying the beginning in which case it will be ignored.
*
* @return The number of bytes into the video to begin playing.
*/
public long getPosition() {
return (position);
}
/**
* The video is going to begin at byte offset Position. Of course this
* could be zero signifying the beginning in which case it will be ignored.
*
* @param l The number of bytes into the video to begin playing.
*/
public void setPosition(long l) {
position = l;
}
/**
* The video is going to begin at seconds. Of course this could
* be zero signifying the beginning in which case it will be ignored.
*
* @return The number of seconds into the video to begin playing.
*/
public int getSeconds() {
return (seconds);
}
/**
* The video is going to begin at seconds. Of course this could
* be zero signifying the beginning in which case it will be ignored.
*
* @param i The number of seconds into the video to begin playing.
*/
public void setSeconds(int i) {
seconds = i;
}
/**
* When we start the mplayer system job we load and start playing the
* video from the command line.
*
* @return The path to the video file.
*/
public String getPath() {
return (path);
}
/**
* When we start the mplayer system job we load and start playing the
* video from the command line.
*
* @param s The path to the video file.
*/
public void setPath(String s) {
path = s;
}
/**
* When auto skip is enabled, mplayer will use an edl file. The file
* is assumed to be the same file name as the Path argument but with
* an ".edl" extension instead of it's current extenstion.
*
* @return True if auto skip is desired.
*/
public boolean isAutoSkip() {
return (autoSkip);
}
/**
* When auto skip is enabled, mplayer will use an edl file. The file
* is assumed to be the same file name as the Path argument but with
* an ".edl" extension instead of it's current extenstion.
*
* @param b True if auto skip is desired.
*/
public void setAutoSkip(boolean b) {
autoSkip = b;
}
private FileWriter getFileWriter() {
return (fileWriter);
}
private void setFileWriter(FileWriter w) {
fileWriter = w;
}
/**
* This method will pass a command to mplayer over stdin.
*
* @param s The given command to send.
*/
public void command(String s) {
if (Util.isLinux()) {
FileWriter w = getFileWriter();
if ((s != null) && (w != null)) {
try {
w.write(s, 0, s.length());
w.flush();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
} else {
// We assume windows or at least non-fifo communication.
SystemJob job = getSystemJob();
if (job != null) {
try {
job.write(s.getBytes(), 0, s.length());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
}
private String computeEDLArgument(String s) {
String result = "";
if ((s != null) && (isAutoSkip())) {
String fname = s.substring(0, s.lastIndexOf("."));
result = "-edl " + fname + ".edl";
}
return (result);
}
private String computeDemuxer() {
String result = "";
MPlayer m = getMPlayer();
if (m != null) {
if (m.isVideoTransportStreamType()) {
//result = "-demuxer mpegts";
} else if (m.isVideoProgramStreamType()) {
//result = "-demuxer mpegps";
}
}
return (result);
}
public String getProgramName() {
String result = "mplayer";
MPlayer m = getMPlayer();
if (m != null) {
result = m.getProgramName();
}
return (result);
}
/**
* {@inheritDoc}
*/
public void start() {
String startParameter = "";
if (getPosition() > 0) {
startParameter = "-sb " + getPosition();
} else if (getSeconds() > 0) {
startParameter = "-ss " + getSeconds();
}
String edltext = computeEDLArgument(getPath());
String userArg = "";
String[] userArgs = getArgs();
if ((userArgs != null) && (userArgs.length > 0)) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < userArgs.length; i++) {
sb.append(userArgs[i]);
sb.append(" ");
}
userArg = sb.toString().trim();
}
String programName = getProgramName();
SystemJob job = null;
String demuxer = computeDemuxer();
String wid = getWindowId();
if (wid != null) {
job = SystemJob.getInstance(
programName + " -wid " + wid + " " + userArg + " " + demuxer
+ " -input nodefault-bindings:conf=/dev/null:"
+ "file=mplayer.fifo" + " -slave " + edltext
+ " " + startParameter + " " + getPath());
} else {
File conf = new File("conf");
File full = new File(conf, "mplayer.conf");
job = SystemJob.getInstance(
programName + " -fs -zoom" + " " + userArg + " " + demuxer
+ " -input nodefault-bindings:conf="
+ full.getAbsolutePath() + ":"
+ "file=mplayer.fifo" + " -slave " + edltext
+ " " + startParameter + " " + getPath());
}
LogUtil.log(LogUtil.DEBUG, "started: " + job.getCommand());
job.addJobListener(this);
setSystemJob(job);
JobContainer jc = JobManager.getJobContainer(job);
setJobContainer(jc);
jc.start();
try {
FileWriter fw = new FileWriter("mplayer.fifo");
setFileWriter(fw);
} catch (IOException ex) {
LogUtil.log(LogUtil.WARNING, "WARNING: FIFO not opened");
}
setTerminate(false);
}
/**
* {@inheritDoc}
*/
public void run() {
while (!isTerminate()) {
JobManager.sleep(getSleepTime());
}
}
/**
* {@inheritDoc}
*/
public void stop() {
JobContainer jc = getJobContainer();
if (jc != null) {
jc.stop();
}
FileWriter w = getFileWriter();
if (w != null) {
try {
w.close();
} catch (IOException ex) {
LogUtil.log(LogUtil.WARNING, "WARNING: could not close FIFO");
}
}
setTerminate(true);
}
/**
* {@inheritDoc}
*/
public void jobUpdate(JobEvent event) {
fireJobEvent(event);
}
}