/*
* 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;
}
}
}