/*
* @(#)JavaDecoder.java 1.8 02/08/21 SMI
*
* Copyright 1998-1999 by Sun Microsystems, Inc.,
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
*
* This software is the confidential and proprietary information
* of Sun Microsystems, Inc. ("Confidential Information"). You
* shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with Sun.
*/
package com.sun.media.codec.audio.mpa;
import javax.media.format.AudioFormat;
import javax.media.Format;
import javax.media.Buffer;
import javax.media.ResourceUnavailableException;
import com.sun.media.util.Arch;
import com.sun.media.JMFSecurity;
import com.sun.media.JMFSecurityManager;
/**
* Class declaration
*
*
* @author Liang He
* @version 1.8, 08/21/02
*/
public class JavaDecoder extends com.sun.media.codec.audio.AudioCodec {
private int pendingDataSize = 0;
private static final int OUTSIZE = 32 * 1024;
private byte[] pendingData = new byte[OUTSIZE];
private codecLib.mpa.Decoder decoder = null;
private codecLib.mpa.FrameInfo info = null;
private boolean expectingSameInputBuffer = false;
private long accumTS = 0;
private AudioFormat aFormat = null;
/**
* Constructor declaration
*
*
* @see
*/
public JavaDecoder() {
inputFormats = new Format[] {
/**
-ivg
Disable MP3 decoding for now.
new AudioFormat(AudioFormat.MPEGLAYER3,
16000.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEGLAYER3,
22050.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEGLAYER3,
24000.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEGLAYER3,
32000.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEGLAYER3,
44100.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEGLAYER3,
48000.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
*/
new AudioFormat(AudioFormat.MPEG,
16000.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEG,
22050.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEG,
24000.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEG,
32000.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEG,
44100.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
new AudioFormat(AudioFormat.MPEG,
48000.,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED, // endian
AudioFormat.SIGNED),
};
}
/**
* Method declaration
*
*
* @return
*
* @see
*/
public String getName() {
return "MPEG Layer 3 Decoder";
}
/**
* Method declaration
*
*
* @param input
*
* @return
*
* @see
*/
public Format[] getSupportedOutputFormats(Format input) {
if (input == null) {
return new Format[] {
new AudioFormat(AudioFormat.LINEAR)
};
} else if (input instanceof AudioFormat) {
AudioFormat af = (AudioFormat) input;
outputFormats = new Format[] {
new AudioFormat(AudioFormat.LINEAR,
af.getSampleRate(),
af.getSampleSizeInBits(),
af.getChannels(),
AudioFormat.BIG_ENDIAN,
/*Arch.isBigEndian()
? AudioFormat.BIG_ENDIAN
: AudioFormat.LITTLE_ENDIAN, */
AudioFormat.SIGNED)
};
} else {
outputFormats = new Format[0];
}
return outputFormats;
}
/**
* Method declaration
*
*
* @throws ResourceUnavailableException
*
* @see
*/
public synchronized void open() throws ResourceUnavailableException {
if (decoder != null) {
close();
}
try {
decoder = new codecLib.mpa.Decoder();
pendingDataSize = 0;
expectingSameInputBuffer = false;
accumTS = 0;
aFormat = (AudioFormat)outputFormat;
// System.err.println("Input format is " + inputFormat);
// System.err.println("Output format is " + outputFormat);
return;
} catch (Throwable e) {
System.out.println("mpa JavaDecoder: open " + e);
}
throw new ResourceUnavailableException("could not open " + getName());
}
/**
* Method declaration
*
*
* @see
*/
public synchronized void close() {
if (decoder != null) {
decoder = null;
}
if (info != null) {
info = null;
}
}
/**
* Method declaration
*
*
* @see
*/
public synchronized void reset() {
if (decoder != null) {
close();
try {
open();
} catch (ResourceUnavailableException rue) {
System.err.println("MP3 Decoder: " + rue);
}
}
}
float[][] fsamp =
new float[codecLib.mpa.Decoder.MAX_CHANNELS][codecLib.mpa.Decoder.SAMPLES_IN_CHANNEL];
int[] fsampOffset = new int[codecLib.mpa.Decoder.MAX_CHANNELS];
int MAXOUTFRAMESIZE = codecLib.mpa.Decoder.MAX_CHANNELS
* codecLib.mpa.Decoder.SAMPLES_IN_CHANNEL
* 2;
int MIMINFRAMESIZE = codecLib.mpa.Decoder.MIN_BYTES_IN_FRAME;
int outFrameSize = 0;
/**
* Method declaration
*
*
* @param in
* @param out
*
* @return
*
* @see
*/
public synchronized int process(Buffer in, Buffer out) {
if (isEOM(in)) {
propagateEOM(out);
return BUFFER_PROCESSED_OK;
}
Object inObject = in.getData();
Object outObject = out.getData();
if (outObject == null) {
outObject = new byte[OUTSIZE];
out.setData(outObject);
}
if (!(inObject instanceof byte[]) ||
!(outObject instanceof byte[])) {
return BUFFER_PROCESSED_FAILED;
}
byte[] inData = (byte[])inObject;
byte[] outData = (byte[])outObject;
int inLength = in.getLength();
int inOffset = in.getOffset();
int outDataSize = outData.length;
int outOffset = 0;
int pendingDataOffset = 0;
int byteCount = 0;
if (!expectingSameInputBuffer) {
if ((pendingDataSize + inLength) <= pendingData.length) {
System.arraycopy(inData, inOffset,
pendingData, pendingDataSize,
inLength);
pendingDataSize += inLength;
}
}
if (decoder != null) {
while (true) {
// Does the output buffer have enough space left?
if ((outDataSize - outOffset) < MAXOUTFRAMESIZE) {
break;
}
// Does the input buffer have enough data?
if (pendingDataSize < MIMINFRAMESIZE) {
break;
}
if (info == null) {
info = new codecLib.mpa.FrameInfo();
try {
decoder.getNextFrameInfo(info,
pendingData,
pendingDataOffset,
pendingDataSize);
outFrameSize = info.getNumberOfSamples()
* info.getNumberOfChannels()
* 2;
} catch (codecLib.mpa.MPADException e) {
//System.out.println("mpa JavaDecoder: getNextFrameInfo " + e);
info = null;
break;
}
}
try {
byteCount = decoder.decode(fsamp, fsampOffset,
pendingData,
pendingDataOffset,
pendingDataSize);
} catch (codecLib.mpa.MPADException e) {
if (e.getState() == codecLib.mpa.Constants.ERR_NOSUPPORT)
return BUFFER_PROCESSED_FAILED;
try {
decoder.getCurrFrameInfo(info);
} catch (codecLib.mpa.MPADException e2) {
//System.out.println("mpa JavaDecoder: getCurrFrameInfo " + e2);
info = null;
break;
}
if (e.getState() == codecLib.mpa.Constants.ERR_NOPREV) {
byteCount = info.getHeaderOffset() + info.getFrameLength();
pendingDataOffset += byteCount;
pendingDataSize -= byteCount;
continue;
}
//System.out.println("mpa JavaDecoder: decode " + e);
info = null;
break;
}
if (info.getNumberOfChannels() == 1) {
codecLib.mpa.OutputConverter.convert(outData, outOffset,
fsamp[0], fsampOffset[0],
info.getNumberOfSamples());
} else {
codecLib.mpa.OutputConverter.convert(outData, outOffset,
fsamp[0], fsampOffset[0],
fsamp[1], fsampOffset[1],
info.getNumberOfSamples());
}
outOffset += outFrameSize;
pendingDataOffset += byteCount;
pendingDataSize -= byteCount;
}
}
// Move the last chunk to the beginning of the pendingData buffer
if (pendingDataOffset != 0) {
System.arraycopy(pendingData, pendingDataOffset,
pendingData, 0,
pendingDataSize);
}
out.setLength(outOffset);
out.setFormat(outputFormat);
if (aFormat != null && accumTS != 0 && in.getTimeStamp() > 0)
out.setTimeStamp(in.getTimeStamp() + aFormat.computeDuration(accumTS));
if (pendingDataSize > 1024) {
expectingSameInputBuffer = true;
accumTS += out.getLength();
return BUFFER_PROCESSED_OK | INPUT_BUFFER_NOT_CONSUMED;
} else {
accumTS = 0;
expectingSameInputBuffer = false;
return BUFFER_PROCESSED_OK;
}
}
}
|