package multimonster.converter.plugin; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; import multimonster.common.Codec; import multimonster.common.Format; import multimonster.common.Structure; import multimonster.common.media.Duration; import multimonster.common.media.MetaData; import multimonster.converter.MetaDataExtractor; import multimonster.converter.plugin.jmx.TCProbeCaller; import org.apache.log4j.Logger; /** * @author Holger Velke * * To change the template for this generated type comment go to * Window - Preferences - Java - Code Generation - Code and Comments */ public class TCProbeExtractor extends MetaDataExtractor { static private Logger log = Logger.getLogger(TCProbeExtractor.class); // recomened for parse Binary static private int TC_PROBE_INFO_SIZE = 4 + TcProbeInfo.STRUCT_SIZE; static private TCProbeCaller caller = null; static private MBeanServer mBeanServer = null; private int tcProbeId = 0; private TcProbeInfo info = null; //state attribute private boolean parsed = false; private int counter = 0; public TCProbeExtractor() { // initialize if (caller == null) { caller = getTCProbeCaller(); } this.tcProbeId = caller.startTCProbeProcess(); // check if everything is ok if (tcProbeId < 0) { // got no tcprobe process this.setReady(false); } else { this.setReady(true); } } static private MBeanServer getMBeanServer() { if (mBeanServer == null) { ArrayList mbeanServers = MBeanServerFactory.findMBeanServer(null); mBeanServer = (MBeanServer) mbeanServers.get(0); } return mBeanServer; } static private TCProbeCaller getTCProbeCaller() { if (mBeanServer == null) getMBeanServer(); if (caller == null) { try { // for retrieval: ObjectName objName = new ObjectName(TCProbeCaller.JMX_NAME); // get the Object-reference (usable only if EJB in the same // JVM) caller = (TCProbeCaller) mBeanServer.invoke( objName, "returnThis", null, null); } catch (Exception e) { log.error("problem getting TCProbeCaller MBean", e); } } return caller; } /* (non-Javadoc) * @see multimonster.converter.MetaDataExtractor#doWork(byte[]) */ protected void doWork(byte[] buf) { // the meta-data-extraction might finish before the pipes are empty // then just read and write the data from input to output. if ((!isFinished()) && (isReady()) && (!isParsed())) { try { boolean moreData = false; moreData = caller.sendDataToTCProbe(tcProbeId, buf); counter += buf.length; if (!moreData) setFinished(); } catch (IOException e) { log.error("problem sending data to tcprobe", e); log.debug("sent " + counter + " bytes to tcprobe"); setFinished(); } } } /* (non-Javadoc) * @see multimonster.converter.MetaDataExtractor#finishWork() */ protected void finishWork() { if (!isFinished()) { caller.finishTCProbeProcess(tcProbeId); setFinished(); } } /* (non-Javadoc) * @see multimonster.converter.MetaDataExtractor#parseFormat() */ protected Format parseFormat() { if (!isParsed()) { parseTCProbeOutput(); } return format; } /* (non-Javadoc) * @see multimonster.converter.MetaDataExtractor#parseMetaData() */ protected MetaData parseMetaData() { if (!isParsed()) { parseTCProbeOutput(); } return metaData; } /** * */ private void parseTCProbeOutput() { byte[] stdout = null; byte[] stderr = null; metaData = new MetaData(); // read data from tcprobe process try { stdout = caller.getTCProbeStdout(tcProbeId); stderr = caller.getTCProbeStderr(tcProbeId); } catch (IOException e) { log.error("problem getting TCProbes output", e); return; } finally { // process not needed any more caller.removeTCProbe(tcProbeId); setParsed(true); } // parse the binary data info = parseBinary(stdout); if (info != null) { format = fillFormat(info); metaData.setDuration(new Duration(info.getTime())); metaData.setNumOfFrames((int) info.getFrames()); log.debug(format.toString()); } else { format = unknownFormat(); log.info("useing UNKNOWN as format"); log.error("tcprobes error message is: " + new String(stderr)); } } /** * parases the binary output of tcprobe. Option '-B' is required when calling tcprobe. * * @param stdout the bynary output of tcprobe */ private TcProbeInfo parseBinary(byte[] stdout) { byte[] dataBytes = null; ByteArrayInputStream stdoutStr = null; info = null; if (stdout.length != TC_PROBE_INFO_SIZE) { log.error("tcprobe output has wrong length: " + stdout.length); } else { try { stdoutStr = new ByteArrayInputStream(stdout); // first 4 bytes are crap - see transcode code for details stdoutStr.skip(4); dataBytes = new byte[stdoutStr.available()]; stdoutStr.read(dataBytes); info = new TcProbeInfo(dataBytes); } catch (IOException e) { log.error("problem parsing tcprobe binary output", e); } } return info; } /** * @return Returns the parsed. */ protected boolean isParsed() { return parsed; } /** * @param parsed The parsed to set. */ protected void setParsed(boolean parsed) { this.parsed = parsed; } private Format fillFormat(TcProbeInfo info) { Format format = new Format(null); //resolution format.setResolutionVertical(info.getHeight()); format.setResolutionHorizontal(info.getWidth()); //frames per second format.setFps((int) info.getFps()); //aspect_ratio - see src: tcprobe.c switch (info.getAsr()) { case 1 : format.setAspectRatio("1:1"); break; case 2 : case 8 : case 12 : format.setAspectRatio("4:3"); break; case 3 : format.setAspectRatio("16:9"); break; case 4 : format.setAspectRatio("2.21:1"); break; default : format.setAspectRatio(""); break; } //codec format.setCodec(TranscodeMagic.getCodec(info.getCodec())); //file type format.setStructure( TranscodeMagic.getStructure(info.getMagic())); format.setBitrate((int) info.getBitrate()); return format; } private Format unknownFormat() { Format format = new Format(null); //resolution format.setResolutionVertical(0); format.setResolutionHorizontal(0); //frames per second format.setFps(0); format.setAspectRatio(""); //codec format.setCodec(new Codec(Codec.UNKNOWN)); //file type format.setStructure(new Structure(Structure.UNKNOWN)); format.setBitrate(0); return format; } }