/*
*
*
* 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.ibm.media.codec.audio.mpegenc;
import java.io.*;
import java.util.*;
import java.awt.*;
import javax.media.*;
import javax.media.format.*;
import javax.media.format.*;
import com.sun.media.*;
/**
* Native Mpeg Encoder Java wrapper
*
* @author Shay Ben-David bendavid@il.ibm.com
**/
public class NativeEncoder 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,1999 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,1999.";
Control[] controls=null;
/* 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 ENCD_MAX_FRAMES = 9;
static final int MAX_INPUT_SIZE = ENCD_MAX_FRAMES * MAX_PCM_FRAME_SIZE * 2;
static final int MAX_OUTPUT_SIZE = ENCD_MAX_FRAMES * MAX_MPEG_STREAM_FRAME_SIZE;
/* Return codes and error codes (do not change these values) */
static final int MPEG_NOERROR = 0;
static final int MPEG_ERROR = 1;
static final int MPEG_FALSE = 0;
static final int MPEG_TRUE = 1;
static final int MPEG_STEREO = 0;
static final int MPEG_JOINT_STEREO = 1;
static final int MPEG_DUAL_CHANNEL = 2;
static final int MPEG_SINGLE_CHANNEL = 3;
// allowed bit rates
static final int[] layer1BitRate_mono= {
32, 64, 96, 128, 160,
192, 224, 256, 288, 320,
352, 384, 416, 448 };
static final int[] layer1BitRate_stereo= {
64, 96, 128, 160,
192, 224, 256, 288, 320,
352, 384, 416, 448 };
static final int[] layer2BitRate_mono= {
32, 48, 56, 64, 80,
96, 112, 128, 160, 192 };
static final int[] layer2BitRate_stereo= {
64, 96, 112, 128, 160,
192, 224, 256, 320, 384 };
/* variables */
// pointer to the MPEG decoder inner data structure
private int[] pdata = new int[1];
private int[] psetup = new int[1];
private int layer;
private int encodingType;
private int bitrate;
private int samplingFrequency;
private int endianess;
private int copyright;
private int original;
private int errorProtect;
private int nChannels;
private int[] in_bytes = new int[1];
private int[] out_bytes = new int[1];
boolean isStarted;
byte[] history=new byte[MAX_INPUT_SIZE];
int historyLength=0;
////////////////////////////////////////////////////////////////////////////
// Methods
public NativeEncoder() {
int[] SamplingFrequencies={32000, 44100,48000};
supportedInputFormats = new AudioFormat[3];
for (int i=0;i<3;i++) {
supportedInputFormats[i]=new AudioFormat(AudioFormat.LINEAR,
SamplingFrequencies[i],
16,
Format.NOT_SPECIFIED,
AudioFormat.LITTLE_ENDIAN,
AudioFormat.SIGNED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
byte[].class
);
}
defaultOutputFormats = new AudioFormat[] { new AudioFormat(AudioFormat.MPEG) };
PLUGIN_NAME="MPEG Audio Encoder";
}
/* native functions prototype */
private static native int nativeOpen (
int[] pdata,
int[] psetup
);
private static native int nativeInit (
int[] pdata,
int[] psetup,
int layer,
int encodingType,
int bitrate,
int samplingFrequency,
int endianess,
int copyright,
int original,
int errorProtect
);
private static native int nativeGetBytesToRead (
int[] pdata,
int[] psetup
);
private static native int nativeEncode (
int[] pdata,
int[] psetup,
byte[] in_buf,
int in_buf_offset,
int in_buf_len,
byte[] out_buf,
int out_buf_offset,
int out_buf_len,
int[] in_bytes,
int[] out_bytes
);
private static native int nativeHandleEOM (
int[] pdata,
int[] pestup,
byte[] out_buf,
int out_buf_offset,
int[] out_bytes
);
private static native int nativeClose (
int[] pdata,
int[] pestup
);
protected Format[] getMatchingOutputFormats(Format in) {
AudioFormat af =(AudioFormat) in;
supportedOutputFormats = new AudioFormat[] {
new AudioFormat(AudioFormat.MPEG,
af.getSampleRate(),
Format.NOT_SPECIFIED,
af.getChannels(),
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
byte[].class
)
};
return supportedOutputFormats;
}
public Format setInputFormat(Format format) {
AudioFormat af=(AudioFormat)super.setInputFormat(format);
if (af==null) {
return null;
}
nChannels=af.getChannels();
samplingFrequency=(int)af.getSampleRate();
endianess= (af.getEndian() == AudioFormat.BIG_ENDIAN) ? MPEG_TRUE : MPEG_FALSE;
bitrate=128 * nChannels;
layer=2;
encodingType= (nChannels==1) ? MPEG_SINGLE_CHANNEL : MPEG_STEREO;
copyright=MPEG_FALSE;
original=MPEG_FALSE;
errorProtect=MPEG_FALSE;
return (Format)af;
}
public void open() throws ResourceUnavailableException{
try {
JMFSecurityManager.loadLibrary("jmutil");
JMFSecurityManager.loadLibrary("jmmpegenc");
nativeOpen(pdata, psetup);
reset();
openControlPanel();
return;
} catch (Throwable t) {
String errMsg= "Unable to load "+PLUGIN_NAME+"\n"+t;
t.printStackTrace();
System.err.println(errMsg);
throw new ResourceUnavailableException(errMsg);
}
}
private void openControlPanel() {
java.awt.Frame controlFrame=new java.awt.Frame(getName()+" Control");
controlFrame.setLayout(new com.sun.media.controls.VFlowLayout(1));
controlFrame.add(new Label(getName()+" Control",Label.CENTER) );
controlFrame.add(new Label( " "));
Control[] c=(Control[]) getControls();
for (int i=0;i<c.length;i++) {
controlFrame.add(c[i].getControlComponent() );
}
controlFrame.pack();
controlFrame.show();
}
public void reset() {
int rc = nativeInit ( pdata, psetup,
layer, encodingType, bitrate, samplingFrequency,
endianess, copyright, original, errorProtect
);
if (rc!=MPEG_NOERROR) {
throw new RuntimeException("MPEG encoder setting failed. rc="+rc);
}
historyLength=0;
isStarted=false;
}
public void close() {
nativeClose (pdata, psetup);
}
public int process(Buffer inputBuffer, Buffer outputBuffer) {
isStarted=true;
int inpLength=inputBuffer.getLength();
int outLength;
int rc, returnResult = 0;
boolean fullFrame=true;
byte[] inpData = (byte[]) inputBuffer.getData();
byte[] outData = validateByteArraySize(outputBuffer, MAX_OUTPUT_SIZE);
int inOffset=inputBuffer.getOffset();
int outOffset=outputBuffer.getOffset();
int neededinput=nativeGetBytesToRead(pdata,psetup);
int inpBytes = neededinput - historyLength;
if (inpBytes>inpLength) {
inpBytes=inpLength;
fullFrame=false;
}
System.arraycopy(inpData,inOffset,history,historyLength, inpBytes);
historyLength += inpBytes;
inOffset += inpBytes;
inpLength -= inpBytes;
inputBuffer.setOffset(inOffset );
inputBuffer.setLength(inpLength );
if (!fullFrame) {
if (inputBuffer.isEOM() ) {
nativeHandleEOM (pdata, psetup,outData,outOffset,out_bytes);
outLength=out_bytes[0];
updateOutput(outputBuffer, outputFormat, outLength, 0);
return BUFFER_PROCESSED_OK;
}
return OUTPUT_BUFFER_NOT_FILLED;
}
rc = nativeEncode (pdata, psetup,
history,0,neededinput,
outData, outOffset, outData.length,
in_bytes, out_bytes);
historyLength=0;
if (rc != MPEG_NOERROR) {
System.out.println("MPEG Audio process error "+rc);
return (BUFFER_PROCESSED_FAILED);
}
outLength=out_bytes[0];
int readInput=in_bytes[0];
updateOutput(outputBuffer, outputFormat, outLength, 0);
return ( INPUT_BUFFER_NOT_CONSUMED | BUFFER_PROCESSED_OK);
}
//================== Control methods ===========================
public java.lang.Object[] getControls() {
if (controls==null) {
controls=new Control[1];
controls[0]=new MpegAudioControlAdapter(this, layer, samplingFrequency,
nChannels, bitrate, 0,0,0,0);
}
return (Object[])controls;
}
boolean setOriginal(int new_original) {
original=new_original;
reset();
return true;
}
boolean setErrorProtect(int new_errorProtect) {
errorProtect=new_errorProtect;
reset();
return true;
}
boolean setCopyright(int new_copyRight) {
copyright=new_copyRight;
reset();
return true;
}
boolean setBitrate(int new_bitrate) {
bitrate=new_bitrate;
reset();
return true;
}
boolean setLayer(int new_layer) {
layer=new_layer;
reset();
return true;
}
boolean SetEncodingType(int new_encodingType) {
encodingType=new_encodingType;
reset();
return true;
}
boolean isControlValid() {
if ( (original != MPEG_FALSE ) &&
(original != MPEG_TRUE )
)
return false;
if ( (errorProtect != MPEG_FALSE ) &&
(errorProtect != MPEG_TRUE )
)
return false;
if ( (copyright != MPEG_FALSE ) &&
(copyright != MPEG_TRUE )
)
return false;
if ( (endianess != MPEG_FALSE ) &&
(endianess != MPEG_TRUE )
)
return false;
if ( (samplingFrequency != 32000 ) &&
(samplingFrequency != 44100 ) &&
(samplingFrequency != 48000 )
)
return false;
if ( (layer != 1 ) &&
(layer != 2 )
)
return false;
if ( (nChannels != 1 ) &&
(nChannels != 2 )
)
return false;
// no support for mpeg dual channel
if ( (encodingType == MPEG_DUAL_CHANNEL ) )
return false;
if ( (encodingType == MPEG_SINGLE_CHANNEL ) &&
(nChannels != 1 )
)
return false;
if ( ( (encodingType == MPEG_STEREO ) ||
(encodingType == MPEG_JOINT_STEREO ) ) &&
(nChannels != 2 )
)
return false;
if (layer == 1) {
if (nChannels == 1) {
for (int i=0;i<layer1BitRate_mono.length;i++) {
if (bitrate==layer1BitRate_mono[i]) {
return true;
}
}
return false;
}
{
for (int i=0;i<layer1BitRate_stereo.length;i++) {
if (bitrate==layer1BitRate_stereo[i]) {
return true;
}
}
return false;
}
}
// layer 2
if (nChannels == 1) {
for (int i=0;i<layer2BitRate_mono.length;i++) {
if (bitrate==layer2BitRate_mono[i]) {
return true;
}
}
return false;
}
{
for (int i=0;i<layer2BitRate_stereo.length;i++) {
if (bitrate==layer2BitRate_stereo[i]) {
return true;
}
}
return false;
}
}
}