/* * @(#)Split.java 1.4 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.awt.*; import java.io.File; import javax.media.*; import javax.media.control.TrackControl; import javax.media.control.QualityControl; import javax.media.Format; import javax.media.format.*; import javax.media.datasink.*; import javax.media.protocol.*; import javax.media.protocol.DataSource; import java.io.IOException; /** * A sample program to split an input media file with multiplexed * audio and video tracks into files of individual elementary track. */ public class Split { SplitDataSource splitDS[]; Object fileSync = new Object(); boolean allDone = false; static String audioExt = null; static String videoExt = null; /** * Main program */ public static void main(String [] args) { String inputURL = null; if (args.length == 0) prUsage(); // Parse the arguments. int i = 0; while (i < args.length) { if (args[i].equals("-a")) { i++; if (i >= args.length) prUsage(); audioExt = args[i]; } else if (args[i].equals("-v")) { i++; if (i >= args.length) prUsage(); videoExt = args[i]; } else { inputURL = args[i]; } i++; } if (inputURL == null) { System.err.println("No input url specified."); prUsage(); } if (audioExt == null) { audioExt = ".wav"; } if (videoExt == null) { videoExt = ".mov"; } // Generate the input media locators. MediaLocator iml; if ((iml = createMediaLocator(inputURL)) == null) { System.err.println("Cannot build media locator from: " + inputURL); System.exit(0); } // Trancode with the specified parameters. Split split = new Split(); if (!split.doIt(iml, audioExt, videoExt)) { System.err.println("Failed to split the input"); } System.exit(0); } /** * Splits the tracks from a multiplexed input. */ public boolean doIt(MediaLocator inML, String audExt, String vidExt) { Processor p; try { System.err.println("- Create processor for: " + inML); p = Manager.createProcessor(inML); } catch (Exception e) { System.err.println("Yikes! Cannot create a processor from the given url: " + e); return false; } System.err.println("- Configure the processor for: " + inML); if (!waitForState(p, p.Configured)) { System.err.println("Failed to configure the processor."); return false; } // If the input is an MPEG file, we'll first convert that to // raw audio and video. if (FileTypeDescriptor.MPEG.equals(fileExtToCD(inML.getRemainder()).getEncoding())) { transcodeMPEGToRaw(p); } System.err.println("- Realize the processor for: " + inML); if (!waitForState(p, p.Realized)) { System.err.println("Failed to realize the processor."); return false; } // Set the JPEG quality to .5. setJPEGQuality(p, 0.5f); // Get the output data streams from the first processor. // Create a SplitDataSource for each of these elementary stream. PushBufferDataSource pbds = (PushBufferDataSource)p.getDataOutput(); PushBufferStream pbs[] = pbds.getStreams(); splitDS = new SplitDataSource[pbs.length]; allDone = false; boolean atLeastOne = false; // Create a file writer for each SplitDataSource to generate // the resulting media file. for (int i = 0; i < pbs.length; i++) { splitDS[i] = new SplitDataSource(p, i); if ((new FileWriter()).write(splitDS[i])) atLeastOne = true; } if (!atLeastOne) { System.err.println("Failed to split any of the tracks."); System.exit(1); } System.err.println("- Start splitting..."); waitForFileDone(); System.err.println(" ...done splitting."); return true; } /** * Callback from the FileWriter when a DataSource is done. */ void doneFile() { synchronized (fileSync) { for (int i = 0; i < splitDS.length; i++) { if (!splitDS[i].done) { return; } } // All done. allDone = true; fileSync.notify(); } } void waitForFileDone() { System.err.print(" "); synchronized (fileSync) { while (!allDone) { try { fileSync.wait(1000); System.err.print("."); } catch (Exception e) {} } } System.err.println(""); } /** * Transcode the MPEG audio to linear and video to JPEG so * we can do the splitting. */ void transcodeMPEGToRaw(Processor p) { TrackControl tc[] = p.getTrackControls(); AudioFormat afmt; for (int i = 0; i < tc.length; i++) { if (tc[i].getFormat() instanceof VideoFormat) tc[i].setFormat(new VideoFormat(VideoFormat.JPEG)); else if (tc[i].getFormat() instanceof AudioFormat) { afmt = (AudioFormat)tc[i].getFormat(); tc[i].setFormat(new AudioFormat(AudioFormat.LINEAR, afmt.getSampleRate(), afmt.getSampleSizeInBits(), afmt.getChannels())); } } } /** * Setting the encoding quality to the specified value on the JPEG encoder. * 0.5 is a good default. */ void setJPEGQuality(Player p, float val) { Control cs[] = p.getControls(); QualityControl qc = null; VideoFormat jpegFmt = new VideoFormat(VideoFormat.JPEG); // Loop through the controls to find the Quality control for // the JPEG encoder. for (int i = 0; i < cs.length; i++) { if (cs[i] instanceof QualityControl && cs[i] instanceof Owned) { Object owner = ((Owned)cs[i]).getOwner(); // Check to see if the owner is a Codec. // Then check for the output format. if (owner instanceof Codec) { Format fmts[] = ((Codec)owner).getSupportedOutputFormats(null); for (int j = 0; j < fmts.length; j++) { if (fmts[j].matches(jpegFmt)) { qc = (QualityControl)cs[i]; qc.setQuality(val); System.err.println("- Set quality to " + val + " on " + qc); break; } } } if (qc != null) break; } } } /** * Utility class to block until a certain state had reached. */ public class StateWaiter implements ControllerListener { Processor p; boolean error = false; StateWaiter(Processor p) { this.p = p; p.addControllerListener(this); } public synchronized boolean waitForState(int state) { switch (state) { case Processor.Configured: p.configure(); break; case Processor.Realized: p.realize(); break; case Processor.Prefetched: p.prefetch(); break; case Processor.Started: p.start(); break; } while (p.getState() < state && !error) { try { wait(1000); } catch (Exception e) { } } //p.removeControllerListener(this); return !(error); } public void controllerUpdate(ControllerEvent ce) { if (ce instanceof ControllerErrorEvent) { error = true; } synchronized (this) { notifyAll(); } } } /** * Block until the given processor has transitioned to the given state. * Return false if the transition failed. */ boolean waitForState(Processor p, int state) { return (new StateWaiter(p)).waitForState(state); } /** * Convert a file name to a content type. The extension is parsed * to determine the content type. */ ContentDescriptor fileExtToCD(String name) { String ext; int p; // Extract the file extension. if ((p = name.lastIndexOf('.')) < 0) return null; ext = (name.substring(p + 1)).toLowerCase(); String type; // Use the MimeManager to get the mime type from the file extension. if ( ext.equals("mp3")) { type = FileTypeDescriptor.MPEG_AUDIO; } else { if ((type = com.sun.media.MimeManager.getMimeType(ext)) == null) return null; type = ContentDescriptor.mimeTypeToPackageName(type); } return new FileTypeDescriptor(type); } /** * Create a media locator from the given string. */ static MediaLocator createMediaLocator(String url) { MediaLocator ml; if (url.indexOf(":") > 0 && (ml = new MediaLocator(url)) != null) return ml; if (url.startsWith(File.separator)) { if ((ml = new MediaLocator("file:" + url)) != null) return ml; } else { String file = "file:" + System.getProperty("user.dir") + File.separator + url; if ((ml = new MediaLocator(file)) != null) return ml; } return null; } static void prUsage() { System.err.println("Usage: java Split -a