package krut.KRUT_Recording; /* * @(#)Merge.java 1.2 01/03/13 * * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved. * * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Sun. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear * facility. Licensee represents and warrants that it will not use or * redistribute the Software for such purposes. */ import java.io.File; import javax.media.*; import javax.media.format.*; import javax.media.protocol.*; import javax.media.protocol.DataSource; import javax.media.datasink.*; import java.util.Vector; /** * Merge the tracks from different inputs and generate a QuickTime file * with the all the merged tracks. Documentation is available on the * Java Media Framework website. */ public class Merge implements ControllerListener, DataSinkListener { Vector sourcesURLs = new Vector(1); Processor [] processors = null; String outputFile = null; String videoEncoding = "JPEG"; String audioEncoding = "LINEAR"; String outputType = FileTypeDescriptor.QUICKTIME; DataSource [] dataOutputs = null; DataSource merger = null; DataSource outputDataSource; Processor outputProcessor; ProcessorModel outputPM; DataSink outputDataSink; MediaLocator outputLocator; VideoFormat videoFormat = null; AudioFormat audioFormat = null; /** This parameter is used to stop the * merging loop in the doMerge() * method. */ boolean done = false; /* This checks if the recording should abort. * It could be done with a local paramameter flag for * aborted, that should be changed from the * EncodingProgressBar instead. */ public krut.KRUT_GUI.EncodingProgressBar myProgressBar; public Merge(String [] args) { parseArgs(args); if (sourcesURLs.size() < 2) { System.err.println("Need at least two source URLs"); showUsage(); } else { doMerge(); } } public Merge(String [] args, krut.KRUT_GUI.EncodingProgressBar p) { myProgressBar = p; parseArgs(args); if (sourcesURLs.size() < 2) { System.err.println("Need at least two source URLs"); showUsage(); } else { doMerge(); } } private void doMerge() { int i = 0; processors = new Processor[sourcesURLs.size()]; dataOutputs = new DataSource[sourcesURLs.size()]; for (i = 0; i < sourcesURLs.size(); i++) { String source = (String) sourcesURLs.elementAt(i); MediaLocator ml = new MediaLocator(source); ProcessorModel pm = new MyPM(ml); try { processors[i] = Manager.createRealizedProcessor(pm); dataOutputs[i] = processors[i].getDataOutput(); processors[i].start(); } catch (Exception e) { System.err.println("Failed to create a processor: " + e); System.exit(-1); } } // Merge the data sources from the individual processors try { merger = Manager.createMergingDataSource(dataOutputs); merger.connect(); merger.start(); } catch (Exception ex) { System.err.println("Failed to merge data sources: " + ex); System.exit(-1); } if (merger == null) { System.err.println("Failed to merge data sources"); System.exit(-1); } /* try { Player p = Manager.createPlayer(merger); new com.sun.media.ui.PlayerWindow(p); } catch (Exception e) { System.err.println("Failed to create player " + e); } */ // Create the output processor ProcessorModel outputPM = new MyPMOut(merger); try { outputProcessor = Manager.createRealizedProcessor(outputPM); outputDataSource = outputProcessor.getDataOutput(); } catch (Exception exc) { System.err.println("Failed to create output processor: " + exc); System.exit(-1); } try { outputLocator = new MediaLocator(outputFile); outputDataSink = Manager.createDataSink(outputDataSource, outputLocator); outputDataSink.open(); } catch (Exception exce) { System.err.println("Failed to create output DataSink: " + exce); System.exit(-1); } outputProcessor.addControllerListener(this); outputDataSink.addDataSinkListener(this); System.err.println("Merging..."); try { outputDataSink.start(); outputProcessor.start(); } catch (Exception excep) { System.err.println("Failed to start file writing: " + excep); System.exit(-1); } int count = 0; while (!done) { try { Thread.currentThread().sleep(100); } catch (InterruptedException ie) { } /** Just check if the merging has been cancelled. * The first try is in case of a NullPointerException, * in case the progress bar has not been * initiated. */ try { if (myProgressBar.cancelled) { try { done = true; outputDataSink.stop(); outputProcessor.stop(); System.out.println("Stopped merge datasink"); } catch (Exception e) { System.out.println("Couldn't stop merge datasink"); System.out.println(e); } } } catch (Exception e) {} if (outputProcessor != null && (int)(outputProcessor.getMediaTime().getSeconds()) > count) { System.err.print("."); count = (int)(outputProcessor.getMediaTime().getSeconds()); } } if (outputDataSink != null) { outputDataSink.close(); } synchronized (this) { if (outputProcessor != null) { outputProcessor.close(); } } System.err.println("Done!"); } public void controllerUpdate(ControllerEvent ce) { if (ce instanceof EndOfMediaEvent) { synchronized (this) { outputProcessor.close(); outputProcessor = null; } } } public void dataSinkUpdate(DataSinkEvent dse) { if (dse instanceof EndOfStreamEvent) { done = true; } else if (dse instanceof DataSinkErrorEvent) { done = true; } } class MyPM extends ProcessorModel { MediaLocator inputLocator; public MyPM(MediaLocator inputLocator) { this.inputLocator = inputLocator; } public ContentDescriptor getContentDescriptor() { return new ContentDescriptor(ContentDescriptor.RAW); } public DataSource getInputDataSource() { return null; } public MediaLocator getInputLocator() { return inputLocator; } public Format getOutputTrackFormat(int index) { return null; } public int getTrackCount(int n) { return n; } public boolean isFormatAcceptable(int index, Format format) { if (videoFormat == null) { videoFormat = new VideoFormat(videoEncoding); } if (audioFormat == null) { audioFormat = new AudioFormat(audioEncoding); } if (format.matches(videoFormat) || format.matches(audioFormat)) return true; else return false; } } class MyPMOut extends ProcessorModel { DataSource inputDataSource; public MyPMOut(DataSource inputDataSource) { this.inputDataSource = inputDataSource; } public ContentDescriptor getContentDescriptor() { return new FileTypeDescriptor(outputType); } public DataSource getInputDataSource() { return inputDataSource; } public MediaLocator getInputLocator() { return null; } public Format getOutputTrackFormat(int index) { return null; } public int getTrackCount(int n) { return n; } public boolean isFormatAcceptable(int index, Format format) { if (videoFormat == null) { videoFormat = new VideoFormat(videoEncoding); } if (audioFormat == null) { audioFormat = new AudioFormat(audioEncoding); } if (format.matches(videoFormat) || format.matches(audioFormat)) return true; else return false; } } private void showUsage() { System.err.println("Usage: Merge <url1> <url2> [<url3> ... ] [-o <out URL>] [-v <video_encoding>] [-a <audio_encoding>] [-t <content_type>]"); } private void parseArgs(String [] args) { int i = 0; while (i < args.length) { if (args[i].equals("-h")) { showUsage(); } else if (args[i].equals("-o")) { i++; outputFile = args[i]; } else if (args[i].equals("-t")) { i++; outputType = args[i]; } else if (args[i].equals("-v")) { i++; videoEncoding = args[i]; } else if (args[i].equals("-a")) { i++; audioEncoding = args[i]; } else { sourcesURLs.addElement(args[i]); } i++; } if (outputFile == null) { outputFile = "file:" + System.getProperty("user.dir") + File.separator + "merged.mov"; } } public static void main(String [] args) { new Merge(args); System.exit(0); } }