/* * 11/19/04 1.0 moved to LGPL. * 12/12/99 Original verion. mdm@techie.com. *----------------------------------------------------------------------- * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 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 Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *---------------------------------------------------------------------- */ package javazoom.jl.converter; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import javazoom.jl.decoder.Bitstream; import javazoom.jl.decoder.Decoder; import javazoom.jl.decoder.Header; import javazoom.jl.decoder.JavaLayerException; import javazoom.jl.decoder.Obuffer; /** * The Converter class implements the conversion of * an MPEG audio file to a .WAV file. To convert an MPEG audio stream, * just create an instance of this class and call the convert() * method, passing in the names of the input and output files. You can * pass in optional ProgressListener and * Decoder.Params objects also to customize the conversion. * * @author MDM 12/12/99 * @since 0.0.7 */ public class Converter { /** * Creates a new converter instance. */ public Converter() { } public synchronized void convert(String sourceName, String destName) throws JavaLayerException { convert(sourceName, destName, null, null); } public synchronized void convert(String sourceName, String destName, ProgressListener progressListener) throws JavaLayerException { convert(sourceName, destName, progressListener, null); } public void convert(String sourceName, String destName, ProgressListener progressListener, Decoder.Params decoderParams) throws JavaLayerException { if (destName.length()==0) destName = null; try { InputStream in = openInput(sourceName); convert(in, destName, progressListener, decoderParams); in.close(); } catch(IOException ioe) { throw new JavaLayerException(ioe.getLocalizedMessage(), ioe); } } public synchronized void convert(InputStream sourceStream, String destName, ProgressListener progressListener, Decoder.Params decoderParams) throws JavaLayerException { if (progressListener==null) progressListener = PrintWriterProgressListener.newStdOut( PrintWriterProgressListener.NO_DETAIL); try { if (!(sourceStream instanceof BufferedInputStream)) sourceStream = new BufferedInputStream(sourceStream); int frameCount = -1; if (sourceStream.markSupported()) { sourceStream.mark(-1); frameCount = countFrames(sourceStream); sourceStream.reset(); } progressListener.converterUpdate(ProgressListener.UPDATE_FRAME_COUNT, frameCount, 0); Obuffer output = null; Decoder decoder = new Decoder(decoderParams); Bitstream stream = new Bitstream(sourceStream); if (frameCount==-1) frameCount = Integer.MAX_VALUE; int frame = 0; long startTime = System.currentTimeMillis(); try { for (; frameupdateID parameter can take these values: * * UPDATE_FRAME_COUNT: param1 is the frame count, or -1 if not known. * UPDATE_CONVERT_COMPLETE: param1 is the conversion time, param2 * is the number of frames converted. */ public void converterUpdate(int updateID, int param1, int param2); /** * If the converter wishes to make a first pass over the * audio frames, this is called as each frame is parsed. */ public void parsedFrame(int frameNo, Header header); /** * This method is called after each frame has been read, * but before it has been decoded. * * @param frameNo The 0-based sequence number of the frame. * @param header The Header rerpesenting the frame just read. */ public void readFrame(int frameNo, Header header); /** * This method is called after a frame has been decoded. * * @param frameNo The 0-based sequence number of the frame. * @param header The Header rerpesenting the frame just read. * @param o The Obuffer the deocded data was written to. */ public void decodedFrame(int frameNo, Header header, Obuffer o); /** * Called when an exception is thrown during while converting * a frame. * * @param t The Throwable instance that * was thrown. * * @return true to continue processing, or false * to abort conversion. * * If this method returns false, the exception * is propagated to the caller of the convert() method. If * true is returned, the exception is silently * ignored and the converter moves onto the next frame. */ public boolean converterException(Throwable t); } /** * Implementation of ProgressListener that writes * notification text to a PrintWriter. */ // REVIEW: i18n of text and order required. static public class PrintWriterProgressListener implements ProgressListener { static public final int NO_DETAIL = 0; /** * Level of detail typically expected of expert * users. */ static public final int EXPERT_DETAIL = 1; /** * Verbose detail. */ static public final int VERBOSE_DETAIL = 2; /** * Debug detail. All frame read notifications are shown. */ static public final int DEBUG_DETAIL = 7; static public final int MAX_DETAIL = 10; private PrintWriter pw; private int detailLevel; static public PrintWriterProgressListener newStdOut(int detail) { return new PrintWriterProgressListener( new PrintWriter(System.out, true), detail); } public PrintWriterProgressListener(PrintWriter writer, int detailLevel) { this.pw = writer; this.detailLevel = detailLevel; } public boolean isDetail(int detail) { return (this.detailLevel >= detail); } public void converterUpdate(int updateID, int param1, int param2) { if (isDetail(VERBOSE_DETAIL)) { switch (updateID) { case UPDATE_CONVERT_COMPLETE: // catch divide by zero errors. if (param2==0) param2 = 1; pw.println(); pw.println("Converted "+param2+" frames in "+param1+" ms ("+ (param1/param2)+" ms per frame.)"); } } } public void parsedFrame(int frameNo, Header header) { if ((frameNo==0) && isDetail(VERBOSE_DETAIL)) { String headerString = header.toString(); pw.println("File is a "+headerString); } else if (isDetail(MAX_DETAIL)) { String headerString = header.toString(); pw.println("Prased frame "+frameNo+": "+headerString); } } public void readFrame(int frameNo, Header header) { if ((frameNo==0) && isDetail(VERBOSE_DETAIL)) { String headerString = header.toString(); pw.println("File is a "+headerString); } else if (isDetail(MAX_DETAIL)) { String headerString = header.toString(); pw.println("Read frame "+frameNo+": "+headerString); } } public void decodedFrame(int frameNo, Header header, Obuffer o) { if (isDetail(MAX_DETAIL)) { String headerString = header.toString(); pw.println("Decoded frame "+frameNo+": "+headerString); pw.println("Output: "+o); } else if (isDetail(VERBOSE_DETAIL)) { if (frameNo==0) { pw.print("Converting."); pw.flush(); } if ((frameNo % 10)==0) { pw.print('.'); pw.flush(); } } } public boolean converterException(Throwable t) { if (this.detailLevel>NO_DETAIL) { t.printStackTrace(pw); pw.flush(); } return false; } } }