/* * @(#)NativeDecoder.java 1.8 02/08/21 * * Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved. */ package com.ibm.media.codec.audio.mpega; import java.io.*; import java.util.*; import javax.media.*; import javax.media.format.*; import javax.media.format.*; import com.sun.media.*; /** GSM to PCM java decoder * @author Shay Ben-David bendavid@haifa.vnet.ibm.com **/ public class NativeDecoder extends com.ibm.media.codec.audio.AudioCodec { //////////////////////////////////////////////////////////////////////////// // Variables /** <FONT COLOR="#FF0000"> * Licensed Materials - Property of IBM <br><br> * "Restricted Materials of IBM" <br><br> * 5746-SM2 <br><br> * (c) Copyright IBM Corporation 1997,1998 All Rights Reserved <br><br> * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with * IBM Corporation.</FONT> * **/ public static final String a_copyright_notice="(c) Copyright IBM Corporation 1997,1998."; /* native functions prototype */ private static native int mpeg_initialization (long[] pdata, int mpeg_quality); private static native int mpeg_audio_decode (long pdata, byte[] in_buf_byte, int in_buf_offset, int in_buf_len, byte[] out_buf_byte, int out_buf_offset, int out_buf_len, int one_frame_flag, int[] num_samples_done, int[]in_bytes_read, int[] samp_freq, int[] stereo); private static native int mpeg_terminate (long pdata); /* define MPEG constants */ // maximum frame size is at layer 2, bitrate 384, sampling freq 32 KHz static final int MAX_MPEG_STREAM_FRAME_SIZE = 1728; static final int MAX_PCM_FRAME_SIZE = 2304; // stereo in Layer II static final int INTERNAL_BUFFER_LEN = 50 * MAX_MPEG_STREAM_FRAME_SIZE; // 50 is arbitray, > 1 second /* define decoding mode: one/many frames per call */ static final int DECODE_ONE_FRAME_ONLY = 0; static final int DECODE_MANY_FRAMES = 1; /* controling the audio quality (valid only for 44.1 KHz sampling rate */ static final int MPEG_CD_QUALITY = 0; static final int MPEG_HIGH_QUALITY = 1; static final int MPEG_MEDIUM_QUALITY = 2; /* Return codes and error codes (do not change these values) */ static final int MPEG_NOERROR = 0; static final int MPEG_ERROR = 1; /* variables */ private int mpegAudioQuality = MPEG_CD_QUALITY; // default: CD private int one_frame_flag = DECODE_MANY_FRAMES; // default: all the frames // pointer to the MPEG decoder inner data structure private long[] pdata = new long[1]; private int[] samp_freq = new int[1]; private int[] stereo = new int[1]; private int[] in_bytes_read = new int[1]; private int[] num_samples_done = new int[1]; private byte[] internalBuffer = new byte[INTERNAL_BUFFER_LEN+20]; // +10 is enough, to prevent over-read inside the dll private int internalBufferDataLen = 0; //////////////////////////////////////////////////////////////////////////// // Methods public NativeDecoder() { supportedInputFormats = new AudioFormat[] { new AudioFormat(AudioFormat.MPEG) }; defaultOutputFormats = new AudioFormat[] { new AudioFormat(AudioFormat.LINEAR) }; PLUGIN_NAME="MPEG Decoder"; } protected Format[] getMatchingOutputFormats(Format in) { AudioFormat af =(AudioFormat) in; supportedOutputFormats = new AudioFormat[] { new AudioFormat( AudioFormat.LINEAR, af.getSampleRate(), 16, af.getChannels(), AudioFormat.LITTLE_ENDIAN, //isBigEndian(), AudioFormat.SIGNED //isSigned()); ) }; return supportedOutputFormats; } public void open() throws ResourceUnavailableException{ try { JMFSecurityManager.loadLibrary("jmutil"); JMFSecurityManager.loadLibrary("jmmpega"); internalBufferDataLen = 0; mpeg_initialization(pdata,mpegAudioQuality); return; } catch (Throwable t) { System.out.println("Unable to load "+PLUGIN_NAME+"\n"+t); } throw new ResourceUnavailableException("Unable to load "+PLUGIN_NAME); } public void reset() { close(); try { open(); } catch (Exception e) { } } public void close() { mpeg_terminate (pdata[0]); } public int process(Buffer inputBuffer, Buffer outputBuffer) { if (!checkInputBuffer(inputBuffer) ) { return BUFFER_PROCESSED_FAILED; } if (isEOM(inputBuffer) ) { propagateEOM(outputBuffer); return BUFFER_PROCESSED_OK; } int inpLength=inputBuffer.getLength(); int outLength=44100*40; /* default output is 1 second of 44.1Khz stereo */ // *40 is arbitray int rc, returnResult = 0; byte[] inpData = (byte[]) inputBuffer.getData(); byte[] outData = validateByteArraySize(outputBuffer, outLength); /* fill input data */ if (INTERNAL_BUFFER_LEN - internalBufferDataLen > inpLength) { System.arraycopy(inpData, inputBuffer.getOffset(), internalBuffer, internalBufferDataLen, inpLength); internalBufferDataLen += inpLength; } else { returnResult |= INPUT_BUFFER_NOT_CONSUMED; } /* decode */ rc = mpeg_audio_decode (pdata[0], internalBuffer, 0, internalBufferDataLen , outData, 0, outData.length, one_frame_flag, num_samples_done, in_bytes_read, samp_freq, stereo); if (rc != MPEG_NOERROR) { // System.out.println("MPEG Audio decoder error"); return (returnResult | BUFFER_PROCESSED_FAILED); } /* if read too much, due to incomplete frame, do not crash */ if (in_bytes_read[0] > internalBufferDataLen) { //if (in_bytes_read[0]-10 > internalBufferDataLen) { // few bytes can be over-read in the dll in end-of-stream... // System.out.println("PROBLEM in Mpeg Audio Decoder: too many bytes have been decoded"); //} in_bytes_read[0] = internalBufferDataLen; } /* meanwhile, always shift data to buf start (not so efficient...) */ System.arraycopy(internalBuffer, in_bytes_read[0], internalBuffer, 0, internalBufferDataLen - in_bytes_read[0]); /* update */ internalBufferDataLen -= in_bytes_read[0]; outLength = num_samples_done[0] << 1; // number of bytes if (outLength > 0) { updateOutput(outputBuffer, outputFormat, outLength, 0); } else { returnResult |= OUTPUT_BUFFER_NOT_FILLED; } return (returnResult | BUFFER_PROCESSED_OK); } }