/*
* @(#)CodecChain.java 1.11 02/08/21
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package com.sun.media.util;
import javax.media.format.*;
import javax.media.format.*;
import javax.media.renderer.VideoRenderer;
import javax.media.*;
import java.util.Vector;
import java.awt.Component;
import java.awt.Dimension;
import com.sun.media.ExtBuffer;
import com.sun.media.SimpleGraphBuilder;
import com.sun.media.Log;
public class CodecChain {
static final int STAGES = 5;
protected Codec [] codecs = null;
protected Buffer [] buffers = null;
protected Format [] formats = null;
protected Renderer renderer = null;
private boolean deallocated = true;
protected boolean firstBuffer = true; // reset this on reset
private boolean rtpFormat = false;
boolean isRawFormat(Format format) {
return false;
}
public void reset() {
firstBuffer = true;
for (int i = 0; i < codecs.length; i++) {
if (codecs[i] != null)
codecs[i].reset();
}
}
/*
* Warning, this buffer's attributes might be modified. So save it in the
* calling routine if necessary.
*/
public int process(Buffer buffer, boolean render) {
int codecNo = 0;
return doProcess(codecNo, buffer, render);
}
// Recursive method
private int doProcess(int codecNo, Buffer input, boolean render) {
Format format = input.getFormat();
if (codecNo == codecs.length) {
// end of chain, render if necessary
if (render) {
// Check for mid-stream format change.
if (renderer != null &&
formats[codecNo] != null &&
formats[codecNo] != format &&
!formats[codecNo].equals(format) &&
!input.isDiscard()) {
// Input format changed.
if (renderer.setInputFormat(format) == null) {
// Format change failed.
Log.error("Monitor failed to handle mid-stream format change:");
Log.error(" old: " + formats[codecNo]);
Log.error(" new: " + format);
return PlugIn.BUFFER_PROCESSED_FAILED;
}
// Format change handled successfully.
formats[codecNo] = format;
}
try {
return renderer.process(input);
} catch (Exception e) {
Log.dumpStack(e);
return PlugIn.BUFFER_PROCESSED_FAILED;
} catch (Error err) {
Log.dumpStack(err);
return PlugIn.BUFFER_PROCESSED_FAILED;
}
} else
return PlugIn.BUFFER_PROCESSED_OK;
} else {
// If raw format, no need to decode just to keep state
if (isRawFormat(format)) {
if (!render) {
return PlugIn.BUFFER_PROCESSED_OK;
}
} else {
// We need to assume these buffers might have Key/NonKey frames
if (!rtpFormat && firstBuffer) {
if ((input.getFlags() & Buffer.FLAG_KEY_FRAME) == 0) {
return PlugIn.BUFFER_PROCESSED_OK;
}
firstBuffer = false;
}
}
// Decode to render or atleast to keep state
// Process this codec
Codec codec = codecs[codecNo];
int returnVal;
// Check for mid-stream format change.
if (codec != null &&
formats[codecNo] != null &&
formats[codecNo] != format &&
!formats[codecNo].equals(format) &&
!input.isDiscard()) {
// Input format changed.
if (codec.setInputFormat(format) == null) {
// Format change failed.
Log.error("Monitor failed to handle mid-stream format change:");
Log.error(" old: " + formats[codecNo]);
Log.error(" new: " + format);
return PlugIn.BUFFER_PROCESSED_FAILED;
}
// Format change handled successfully.
formats[codecNo] = format;
}
do {
//System.err.println("format = " + input.getFormat());
try {
returnVal = codec.process(input, buffers[codecNo]);
} catch (Exception e) {
Log.dumpStack(e);
return PlugIn.BUFFER_PROCESSED_FAILED;
} catch (Error err) {
Log.dumpStack(err);
return PlugIn.BUFFER_PROCESSED_FAILED;
}
//System.err.println("codecNo: " + codecNo + " return val = " + returnVal);
if (returnVal == PlugIn.BUFFER_PROCESSED_FAILED)
return PlugIn.BUFFER_PROCESSED_FAILED;
if ((returnVal & PlugIn.OUTPUT_BUFFER_NOT_FILLED) == 0) {
//System.err.println("Calling process");
if (!(buffers[codecNo].isDiscard() || buffers[codecNo].isEOM()))
doProcess(codecNo + 1, buffers[codecNo], render);
buffers[codecNo].setOffset(0);
buffers[codecNo].setLength(0);
buffers[codecNo].setFlags(0);
}
} while ((returnVal & PlugIn.INPUT_BUFFER_NOT_CONSUMED) != 0);
return returnVal;
}
}
public Component getControlComponent() {
return null;
}
public boolean prefetch() {
if (!deallocated)
return true;
try {
renderer.open();
} catch (ResourceUnavailableException e) {
return false;
}
renderer.start();
deallocated = false;
return true;
}
public void deallocate() {
if (deallocated)
return;
if (renderer != null)
renderer.close();
deallocated = true;
}
public void close() {
for (int i = 0; i < codecs.length; i++) {
codecs[i].close();
}
if (renderer != null)
renderer.close();
}
protected boolean buildChain(Format input) {
Vector pluginList;
Vector formatList = new Vector(10);
if ((pluginList = SimpleGraphBuilder.findRenderingChain(input, formatList)) == null)
return false;
int len = pluginList.size();
codecs = new Codec[len-1];
buffers = new ExtBuffer[len-1];
formats = new Format[len];
formats[0] = input;
Log.comment("Monitor codec chain:");
for (int j = 0; j < codecs.length; j++) {
codecs[j] = (Codec) pluginList.elementAt(len-j-1);
// Output format for each codec.
formats[j+1] = (Format) formatList.elementAt(len-j-2);
buffers[j] = new ExtBuffer();
buffers[j].setFormat(formats[j+1]);
Log.write(" codec: " + codecs[j]);
Log.write(" format: " + formats[j]);
}
renderer = (Renderer)pluginList.elementAt(0);
Log.write(" renderer: " + renderer);
Log.write(" format: " + formats[codecs.length] + "\n");
if (input.getEncoding() != null) {
String enc = input.getEncoding().toUpperCase();
if (enc.endsWith("RTP"))
rtpFormat = true;
}
return true;
}
}
|