/*
* @(#)NativeDecoder.java 1.12 00/11/06
*
* 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.video.jpeg;
import javax.media.*;
import javax.media.Format;
import javax.media.format.*;
import javax.media.control.*;
import java.awt.Dimension;
import java.awt.Component;
import com.sun.media.*;
import com.sun.media.util.*;
public final class NativeDecoder extends BasicCodec {
// I/O formats
private VideoFormat inputFormat = null;
private RGBFormat outputFormat = null;
// Have we loaded the native library?
private static boolean loaded = false;
// Assume we can load it.
private static boolean canLoad = true;
// Pointer to native structure
private int peer = 0;
int returnVal = 0;
private boolean dropFrame = false;
private boolean minimal = false;
private int decimation = -1;
/****************************************************************
* Codec Methods
****************************************************************/
// Initialize default formats.
public NativeDecoder() {
inputFormats = new VideoFormat[2];
inputFormats[0] = new VideoFormat(VideoFormat.JPEG);
inputFormats[1] = new VideoFormat(VideoFormat.MJPG);
outputFormats = new RGBFormat[1];
outputFormats[0] = new RGBFormat();
FrameProcessingControl fpc = new FrameProcessingControl() {
public boolean setMinimalProcessing(boolean newMinimal) {
minimal = newMinimal;
return minimal;
}
public void setFramesBehind(float frames) {
if (frames >= 1)
dropFrame = true;
else
dropFrame = false;
}
public Component getControlComponent() {
return null;
}
public int getFramesDropped() {
return 0; ///XXX not implemented
}
};
controls = new Control[1];
controls[0] = fpc;
}
protected Format getInputFormat() {
return inputFormat;
}
protected Format getOutputFormat() {
return outputFormat;
}
// Return supported output formats
public Format [] getSupportedOutputFormats(Format in) {
if (in == null)
return outputFormats;
// Make sure the input is RGB video format
if (!verifyInputFormat(in))
return new Format[0];
return computeOutputFormats(in);
}
private boolean verifyInputFormat(Format input) {
if (!(input instanceof VideoFormat))
return false;
if (input.getEncoding().equalsIgnoreCase(VideoFormat.JPEG) ||
input.getEncoding().equalsIgnoreCase(VideoFormat.MJPG) )
return true;
return false;
}
public Format setInputFormat(Format input) {
if (!verifyInputFormat(input))
return null;
inputFormat = (VideoFormat) input;
if (opened) {
close();
outputFormat = updateRGBFormat(inputFormat, outputFormat);
}
return input;
}
public Format setOutputFormat(Format output) {
if (matches(output, outputFormats) == null){
return null;
}
outputFormat = (RGBFormat) output;
return output;
}
private final VideoFormat[] computeOutputFormats(Format in) {
// Calculate the properties
VideoFormat jpeg = (VideoFormat) in;
Dimension size = jpeg.getSize();
if (size == null)
size = new Dimension(320, 240);
int area = ((size.width + 7) & ~7) * ((size.height + 7) & ~7);
RGBFormat [] rgb = new RGBFormat[] {
new RGBFormat(size,
area * 3,
Format.byteArray,
jpeg.getFrameRate(),
24,
1, 2, 3,
3, size.width * 3,
RGBFormat.TRUE,
Format.NOT_SPECIFIED),
new RGBFormat(size,
area * 3,
Format.byteArray,
jpeg.getFrameRate(),
24,
3, 2, 1,
3, size.width * 3,
RGBFormat.TRUE,
Format.NOT_SPECIFIED),
new RGBFormat(size,
area,
Format.intArray,
jpeg.getFrameRate(),
32,
0xFF0000, 0xFF00, 0xFF,
1, size.width,
RGBFormat.TRUE,
Format.NOT_SPECIFIED),
new RGBFormat(size,
area,
Format.intArray,
jpeg.getFrameRate(),
32,
0xFF, 0xFF00, 0xFF0000,
1, size.width,
RGBFormat.TRUE,
Format.NOT_SPECIFIED),
new RGBFormat(size,
area * 3,
Format.byteArray,
jpeg.getFrameRate(),
24,
1, 2, 3,
3, size.width * 3,
RGBFormat.FALSE,
Format.NOT_SPECIFIED),
new RGBFormat(size,
area * 3,
Format.byteArray,
jpeg.getFrameRate(),
24,
3, 2, 1,
3, size.width * 3,
RGBFormat.FALSE,
Format.NOT_SPECIFIED),
new RGBFormat(size,
area,
Format.intArray,
jpeg.getFrameRate(),
32,
0xFF0000, 0xFF00, 0xFF,
1, size.width,
RGBFormat.FALSE,
Format.NOT_SPECIFIED),
new RGBFormat(size,
area,
Format.intArray,
jpeg.getFrameRate(),
32,
0xFF, 0xFF00, 0xFF0000,
1, size.width,
RGBFormat.FALSE,
Format.NOT_SPECIFIED)
};
return rgb;
}
public void open() throws ResourceUnavailableException {
if (!canLoad)
throw new ResourceUnavailableException("Unable to load" +
" native JPEG converter");
if (!loaded) {
try {
JMFSecurityManager.loadLibrary( "jmutil");
JMFSecurityManager.loadLibrary( "jmjpeg");
loaded = true;
} catch (Throwable t) {
canLoad = false;
throw new ResourceUnavailableException("Unable to load " +
"native JPEG decoder");
}
}
if (inputFormat == null || outputFormat == null)
throw new ResourceUnavailableException("Formats not set " +
"on the JPEG decoder");
if (peer != 0)
close();
Dimension size = inputFormat.getSize();
try {
peer = initJPEGDecoder(size.width, size.height);
} catch (Throwable t) {
}
if (inputFormat instanceof JPEGFormat) {
decimation = ((JPEGFormat)inputFormat).getDecimation();
}
if (peer == 0)
throw new ResourceUnavailableException("Unable to initialize JPEG decoder");
super.open();
}
public synchronized void close() {
if (peer != 0)
freeJPEGDecoder(peer);
peer = 0;
super.close();
}
public void reset() {
// Anything to do?
}
public synchronized int process(Buffer inBuffer, Buffer outBuffer) {
Object header = null;
Format inFormat;
Format outFormat = null;
byte [] inData;
boolean flipped;
// EndOfMedia?
if (isEOM(inBuffer)) {
propagateEOM(outBuffer);
return BUFFER_PROCESSED_OK;
}
// Dropping frames?
if (minimal || dropFrame) {
outBuffer.setFlags(outBuffer.getFlags() | Buffer.FLAG_DISCARD);
return BUFFER_PROCESSED_OK;
}
inFormat = inBuffer.getFormat();
inData = (byte[]) inBuffer.getData();
if (inBuffer.getLength() < 1)
return BUFFER_PROCESSED_OK;
if (!inFormat.equals(inputFormat)) {
setInputFormat(inFormat);
close();
}
if (outFormat == null) {
outBuffer.setFormat(outputFormat);
outFormat = outputFormat;
}
Object outData = validateData(outBuffer, 0, true);
flipped = ((RGBFormat)outFormat).getFlipped() == RGBFormat.TRUE;
if (peer == 0) {
try {
open();
} catch (ResourceUnavailableException re) {
return BUFFER_PROCESSED_FAILED;
}
}
Dimension size = inputFormat.getSize();
synchronized (NativeEncoder.processLock) {
if (outData instanceof byte[]) {
returnVal =
decodeJPEGToByte(peer,
inData,
inBuffer.getLength(),
size.width,
size.height,
(byte[]) outData,
outputFormat.getMaxDataLength(),
flipped,
outputFormat.getRedMask(),
outputFormat.getGreenMask(),
outputFormat.getBlueMask(),
outputFormat.getBitsPerPixel());
outBuffer.setLength(size.width * size.height *
outputFormat.getBitsPerPixel() / 8);
} else if (outData instanceof int[]) {
returnVal =
decodeJPEGToInt(peer,
inData,
inBuffer.getLength(),
size.width,
size.height,
(int[]) outData,
outputFormat.getMaxDataLength(),
flipped,
outputFormat.getRedMask(),
outputFormat.getGreenMask(),
outputFormat.getBlueMask(),
outputFormat.getBitsPerPixel());
outBuffer.setLength(size.width * size.height);
} else if (outData instanceof NBA) {
NBA nba = (NBA) outData;
returnVal =
decodeJPEGToNBA(peer,
inData,
inBuffer.getLength(),
size.width,
size.height,
nba.getNativeData(),
outputFormat.getMaxDataLength(),
flipped,
outputFormat.getRedMask(),
outputFormat.getGreenMask(),
outputFormat.getBlueMask(),
outputFormat.getBitsPerPixel());
outBuffer.setLength(size.width * size.height);
if (outputFormat.getDataType() == Format.byteArray)
outBuffer.setLength(outBuffer.getLength() *
outputFormat.getBitsPerPixel() / 8);
}
}
if (returnVal > 0) {
outBuffer.setOffset(0);
inBuffer.setLength(0);
outBuffer.setFlags(outBuffer.getFlags() | Buffer.FLAG_KEY_FRAME);
outBuffer.setTimeStamp(inBuffer.getTimeStamp());
return BUFFER_PROCESSED_OK;
}
outBuffer.setDiscard(true);
return BUFFER_PROCESSED_FAILED;
}// end of process()
protected void finalize() {
close();
}
public String getName() {
return "JPEG Decoder";
}
/****************************************************************
* Native Methods
****************************************************************/
// Initializes the native decoder
private native int initJPEGDecoder(int width, int height);
/*
* Decodes the JPEG data and returns the output length (positive)
* Returns zero if it couldn't decode, or a negative value to indicate
* the error.
*/
private native int decodeJPEGToByte(int peer, byte [] inData, int inLength,
int width, int height,
byte [] outData, int outLength,
boolean flipped,
int red, int green, int blue,
int bitsPerPixel);
/*
* Decodes the JPEG data and returns the output length (positive)
* Returns zero if it couldn't decode, or a negative value to indicate
* the error.
*/
private native int decodeJPEGToInt(int peer, byte [] inData, int inLength,
int width, int height,
int [] outData, int outLength,
boolean flipped,
int red, int green, int blue,
int bitsPerPixel);
/*
* Decodes the JPEG data and returns the output length (positive)
* Returns zero if it couldn't decode, or a negative value to indicate
* the error.
*/
private native int decodeJPEGToNBA(int peer, byte [] inData, int inLength,
int width, int height,
long outData, int outLength,
boolean flipped,
int red, int green, int blue,
int bitsPerPixel);
// Frees any native structures
private native boolean freeJPEGDecoder(int peer);
}
|