NativeEncoderpublic class NativeEncoder extends BasicCodec
Fields Summary |
---|
private RGBFormat | inputFormat | private VideoFormat | outputFormat | private static boolean | loaded | private static boolean | canLoad | private int | peer | private static int | QSCALE | private float | quality | private float | prevQuality | private boolean | isMotionJPEG | private boolean | firstFrame | private int | PACKET_SIZE | private int | currentSeq | private long | timestamp | private byte[] | rtp_data | static Integer | processLock | private int | copyLength | private boolean | newframe | private int | current_offset | int | returnVal | private boolean | dropFrame | private boolean | minimal | private static final int | DEFAULT_FRAMERATE | private byte[] | mjpgExtraBytes |
Constructors Summary |
---|
public NativeEncoder()Codec Methods
// Initialize default formats.
inputFormats = new RGBFormat[1];
inputFormats[0] = new RGBFormat();
outputFormats = new VideoFormat[2];
outputFormats[0] = new JPEGFormat();
outputFormats[1] = new VideoFormat(VideoFormat.MJPG);
class QCA extends QualityAdapter implements Owned {
public QCA() {
super(0.6f, 0f, 1f, true);
}
public float setQuality(float newValue) {
quality = super.setQuality(newValue);
return quality;
}
public String getName() {
return "JPEG Quality";
}
public Object getOwner() {
return NativeEncoder.this;
}
}
QualityControl qualityControl = new QCA();
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[2];
controls[0] = qualityControl;
controls[1] = fpc;
|
Methods Summary |
---|
public synchronized void | close()
if (peer != 0)
freeJPEGEncoder(peer);
peer = 0;
super.close();
| private native int | encodeJPEG(int peer, java.lang.Object inData, long inBytes, int width, int height, byte[] outData, int length, int quality, int decimation, boolean flipped)
| public void | finalize()
close();
| private native boolean | freeJPEGEncoder(int peer)
| protected javax.media.Format | getInputFormat()
return inputFormat;
| public java.lang.String | getName()
return "JPEG Encoder";
| protected javax.media.Format | getOutputFormat()
return outputFormat;
| public javax.media.Format[] | getSupportedOutputFormats(javax.media.Format in)
if (in == null)
return outputFormats;
// Make sure the input is RGB video format
if (!verifyInputFormat(in))
return new Format[0];
Format out [] = new Format[2];
RGBFormat rgb = (RGBFormat) in;
Dimension size = rgb.getSize();
int maxDataLength = size.width * size.height * 3;
VideoFormat jpeg = new JPEGFormat(size, maxDataLength,
Format.byteArray,
rgb.getFrameRate(),
// -- hsy for bugid 4414481
//(int) (qfToQuality(quality)),
//qfToType(quality));
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED);
VideoFormat mjpg = new AviVideoFormat(VideoFormat.MJPG,
size, maxDataLength,
Format.byteArray,
rgb.getFrameRate(),
1, 24, maxDataLength,
0, 0, 0, 0,
mjpgExtraBytes);
out[0] = jpeg;
out[1] = mjpg;
return out;
| private native int | initJPEGEncoder(int width, int height, int quality, int decimation)Native Methods
| public static void | main(java.lang.String[] args)Test Code
int width = 320;
int height = 240;
RGBFormat in = new RGBFormat(new Dimension(width, height),
width * height * 3,
Format.byteArray,
Format.NOT_SPECIFIED, // frame rate
24,
1, 2, 3, 3, width * 3,
Format.FALSE, // flipped
Format.NOT_SPECIFIED // endian
);
VideoFormat out = new VideoFormat(VideoFormat.JPEG,
new Dimension(width, height),
width * height * 3,
Format.byteArray,
// frame rate
Format.NOT_SPECIFIED
);
NativeEncoder e = new NativeEncoder();
if (e.setInputFormat(in) != null) {
if (e.setOutputFormat(out) != null) {
try {
e.open();
} catch (ResourceUnavailableException rue) {
System.err.println("Couldn't open encoder");
System.exit(0);
}
byte [] rgbData = new byte[width * height * 3];
System.err.println("Filling rgb data");
for (int i = 0; i < width * height * 3; i++)
rgbData[i] = (byte) (((i % 3) * (i % width)) % 255);
System.err.println("Encoding");
Buffer inBuffer = new Buffer();
inBuffer.setFormat(in);
inBuffer.setData(rgbData);
inBuffer.setLength(width * height * 3);
Buffer outBuffer = new Buffer();
outBuffer.setFormat(out);
int result = e.process(inBuffer, outBuffer);
System.err.println("Result = " + result);
e.close();
}
}
System.exit(0);
| public void | open()
if (!canLoad)
throw new ResourceUnavailableException("Unable to load" +
" native JPEG converter");
// Size restriction - 8x8
Dimension size = inputFormat.getSize();
if (size == null || (size.width % 8) != 0 || (size.height % 8) != 0 ) {
Log.error("Class: " + this);
Log.error(" can only encode in sizes of multiple of 8 pixels.");
throw new ResourceUnavailableException("Unable to encode in size " + size);
}
if (!loaded) {
try {
JMFSecurityManager.loadLibrary( "jmutil");
JMFSecurityManager.loadLibrary( "jmjpeg");
loaded = true;
} catch (Throwable t) {
canLoad = false;
throw new ResourceUnavailableException("Unable to load " +
"native JPEG encoder");
}
}
if (inputFormat == null || outputFormat == null)
throw new ResourceUnavailableException("Formats not set " +
"on the JPEG encoder");
if (peer != 0)
close();
try {
peer = initJPEGEncoder(size.width, size.height,
(int) qfToQuality(quality),
qfToDecimation(quality));
firstFrame = true;
} catch (Throwable t) {
}
if (peer == 0)
throw new ResourceUnavailableException("Unable to initialize JPEG encoder");
super.open();
| public synchronized int | process(javax.media.Buffer inBuffer, javax.media.Buffer outBuffer)
Object header = null;
float changeQuality;
int changeDecimation;
Format inFormat;
Object inData;
long inBytes;
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 = getInputData(inBuffer);
inBytes = getNativeData(inData);
flipped = ((RGBFormat) inFormat).getFlipped() == Format.TRUE;
//if (outputFormat.getEncoding().equals(VideoFormat.JPEG)){
byte [] outData = (byte[]) outBuffer.getData();
if (outData == null ||
outData.length < outputFormat.getMaxDataLength()) {
outData = new byte[outputFormat.getMaxDataLength()];
outBuffer.setData(outData);
}
outBuffer.setFormat(outputFormat);
if (prevQuality != quality) {
prevQuality = quality;
changeQuality = qfToQuality(quality);
outputFormat = new JPEGFormat(outputFormat.getSize(),
outputFormat.getMaxDataLength(),
Format.byteArray,
outputFormat.getFrameRate(),
(int) qfToQuality(quality),
qfToType(quality));
close();
// Allow changing decimation only if this is the first encoded frame
if (firstFrame)
changeDecimation = qfToDecimation(quality);
else
changeDecimation = -1;
} else { // dont change quality
changeQuality = -1;
changeDecimation = -1;
}
if (peer == 0) {
try {
open();
} catch (ResourceUnavailableException re) {
return BUFFER_PROCESSED_FAILED;
}
}
Dimension size = inputFormat.getSize();
synchronized (processLock) {
returnVal =
encodeJPEG(peer,
inData,
inBytes,
size.width,
size.height,
outData,
outData.length,
(int) changeQuality,
(int) changeDecimation,
flipped);
}
firstFrame = false;
if (returnVal > 0) {
outBuffer.setLength(returnVal);
outBuffer.setOffset(0);
inBuffer.setLength(0);
outBuffer.setFlags(Buffer.FLAG_KEY_FRAME);
outBuffer.setTimeStamp(inBuffer.getTimeStamp());
outBuffer.setFormat(outputFormat);
return BUFFER_PROCESSED_OK;
}
outBuffer.setDiscard(true);
return BUFFER_PROCESSED_FAILED;
| protected int | qfToDecimation(float quality)
if (isMotionJPEG)
return 2;
if (quality >= 0.8f) {
if (quality >= 0.90f)
return 4;
else
return 2;
} else
return 1;
| protected float | qfToQuality(float quality)
if (quality < 0.1f)
quality = 0.1f;
if (isMotionJPEG)
return quality * (float) QSCALE;
if (quality < 0.8f) {
return quality * 1.25f * QSCALE;
} else {
return (float) QSCALE;
}
| protected int | qfToType(float quality)
switch (qfToDecimation(quality)) {
case 1:
return JPEGFormat.DEC_420;
case 2:
return JPEGFormat.DEC_422;
case 4:
return JPEGFormat.DEC_444;
}
return 1;
| public void | reset()
// Anything to do?
| public javax.media.Format | setInputFormat(javax.media.Format input)
if (!verifyInputFormat(input))
return null;
inputFormat = (RGBFormat) input;
if (opened) {
close();
Dimension size = inputFormat.getSize();
int maxDataLength = size.width * size.height * 3;
if (outputFormat instanceof JPEGFormat)
outputFormat = new JPEGFormat(size,
maxDataLength,
Format.byteArray,
inputFormat.getFrameRate(),
(int) qfToQuality(quality),
qfToType(quality));
else
outputFormat = new AviVideoFormat(VideoFormat.MJPG,
size, maxDataLength,
Format.byteArray,
inputFormat.getFrameRate(),
1, 24, maxDataLength,
0, 0, 0, 0,
mjpgExtraBytes);
}
return input;
| public javax.media.Format | setOutputFormat(javax.media.Format output)
if (matches(output, outputFormats) == null){
return null;
}
outputFormat = (VideoFormat) output;
if (outputFormat.getEncoding().equalsIgnoreCase(VideoFormat.MJPG))
isMotionJPEG = true;
else
isMotionJPEG = false;
return output;
| private boolean | verifyInputFormat(javax.media.Format input)
if (!(input instanceof RGBFormat))
return false;
RGBFormat rgb = (RGBFormat) input;
if ( rgb.getDataType() != Format.byteArray ||
rgb.getBitsPerPixel() != 24 ||
rgb.getRedMask() != 3 ||
rgb.getGreenMask() != 2 ||
rgb.getBlueMask() != 1 ||
rgb.getSize() == null ||
rgb.getLineStride() < rgb.getSize().width ||
rgb.getPixelStride() != 3 )
return false;
return true;
|
|