/* * @(#)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; } }