--- /dev/null
+package Analysis.SSJava;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+
+import IR.AnnotationDescriptor;
+import IR.ClassDescriptor;
+import IR.Descriptor;
+import IR.MethodDescriptor;
+import IR.State;
+import IR.SymbolTable;
+import IR.TaskDescriptor;
+import IR.TypeDescriptor;
+import IR.VarDescriptor;
+import IR.Tree.ArrayAccessNode;
+import IR.Tree.ArrayInitializerNode;
+import IR.Tree.AssignmentNode;
+import IR.Tree.AtomicNode;
+import IR.Tree.BlockExpressionNode;
+import IR.Tree.BlockNode;
+import IR.Tree.BlockStatementNode;
+import IR.Tree.CastNode;
+import IR.Tree.ClassTypeNode;
+import IR.Tree.ContinueBreakNode;
+import IR.Tree.CreateObjectNode;
+import IR.Tree.DeclarationNode;
+import IR.Tree.ExpressionNode;
+import IR.Tree.FieldAccessNode;
+import IR.Tree.IfStatementNode;
+import IR.Tree.InstanceOfNode;
+import IR.Tree.Kind;
+import IR.Tree.LiteralNode;
+import IR.Tree.LoopNode;
+import IR.Tree.MethodInvokeNode;
+import IR.Tree.NameNode;
+import IR.Tree.OffsetNode;
+import IR.Tree.OpNode;
+import IR.Tree.ReturnNode;
+import IR.Tree.SubBlockNode;
+import IR.Tree.SwitchBlockNode;
+import IR.Tree.SwitchLabelNode;
+import IR.Tree.SwitchStatementNode;
+import IR.Tree.SynchronizedNode;
+import IR.Tree.TagDeclarationNode;
+import IR.Tree.TaskExitNode;
+import IR.Tree.TertiaryNode;
+
+public class LinearTypeCheck {
+
+ State state;
+ SSJavaAnalysis ssjava;
+ String needToNullify = null;
+
+ Hashtable<MethodDescriptor, Set<VarDescriptor>> md2DelegateParamSet;
+
+ public LinearTypeCheck(SSJavaAnalysis ssjava, State state) {
+ this.ssjava = ssjava;
+ this.state = state;
+ md2DelegateParamSet = new Hashtable<MethodDescriptor, Set<VarDescriptor>>();
+ }
+
+ public void linearTypeCheck() {
+
+ // first, parsing DELEGATE annotation from method declarations
+ Iterator it = state.getClassSymbolTable().getDescriptorsIterator();
+ while (it.hasNext()) {
+ ClassDescriptor cd = (ClassDescriptor) it.next();
+ for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
+ MethodDescriptor md = (MethodDescriptor) method_it.next();
+ parseAnnotations(md);
+ }
+ }
+ System.out.println("###");
+ System.out.println("md2DelegateParamSet=" + md2DelegateParamSet);
+
+ // second, check the linear type
+ it = state.getClassSymbolTable().getDescriptorsIterator();
+ while (it.hasNext()) {
+ ClassDescriptor cd = (ClassDescriptor) it.next();
+ for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
+ MethodDescriptor md = (MethodDescriptor) method_it.next();
+ if (ssjava.needTobeAnnotated(md)) {
+ checkMethodBody(cd, md);
+ }
+ }
+ }
+
+ }
+
+ private void parseAnnotations(MethodDescriptor md) {
+
+ for (int i = 0; i < md.numParameters(); i++) {
+ // process annotations on method parameters
+ VarDescriptor vd = (VarDescriptor) md.getParameter(i);
+
+ Vector<AnnotationDescriptor> annotationVec = vd.getType().getAnnotationMarkers();
+
+ for (int anIdx = 0; anIdx < annotationVec.size(); anIdx++) {
+ AnnotationDescriptor ad = annotationVec.elementAt(anIdx);
+ if (ad.getMarker().equals(SSJavaAnalysis.DELEGATE)) {
+
+ Set<VarDescriptor> delegateSet = md2DelegateParamSet.get(md);
+ if (delegateSet == null) {
+ delegateSet = new HashSet<VarDescriptor>();
+ md2DelegateParamSet.put(md, delegateSet);
+ }
+ delegateSet.add(vd);
+ }
+ }
+
+ }
+
+ }
+
+ private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
+ BlockNode bn = state.getMethodBody(md);
+ checkBlockNode(md, md.getParameterTable(), bn);
+ }
+
+ private void checkBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) {
+ for (int i = 0; i < bn.size(); i++) {
+ BlockStatementNode bsn = bn.get(i);
+ checkBlockStatementNode(md, bn.getVarTable(), bsn);
+ }
+ }
+
+ private void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
+ BlockStatementNode bsn) {
+
+ if (needToNullify != null) {
+ if (!checkNullifying(bsn)) {
+ throw new Error(
+ "Reference field, which is read by a method, should be assigned to null before executing any following statement of the reference copy statement at "
+ + md.getClassDesc().getSourceFileName() + "::" + bsn.getNumLine());
+ }
+ }
+
+ switch (bsn.kind()) {
+
+ case Kind.BlockExpressionNode:
+ checkBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn);
+ return;
+
+ case Kind.DeclarationNode:
+ checkDeclarationNode(md, nametable, (DeclarationNode) bsn);
+ return;
+
+ case Kind.IfStatementNode:
+ checkIfStatementNode(md, nametable, (IfStatementNode) bsn);
+ return;
+
+ case Kind.SwitchStatementNode:
+ checkSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
+ return;
+
+ case Kind.LoopNode:
+ checkLoopNode(md, nametable, (LoopNode) bsn);
+ return;
+
+ case Kind.ReturnNode:
+ checkReturnNode(md, nametable, (ReturnNode) bsn);
+ return;
+
+ case Kind.SubBlockNode:
+ checkSubBlockNode(md, nametable, (SubBlockNode) bsn);
+ return;
+
+ case Kind.SynchronizedNode:
+ checkSynchronizedNode(md, nametable, (SynchronizedNode) bsn);
+ return;
+ }
+
+ throw new Error();
+ }
+
+ private void checkSynchronizedNode(MethodDescriptor md, SymbolTable nametable,
+ SynchronizedNode sbn) {
+ checkBlockNode(md, nametable, sbn.getBlockNode());
+ // todo this could be Object
+ checkExpressionNode(md, nametable, sbn.getExpr());
+ }
+
+ private void checkReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn) {
+ if (rn.getReturnExpression() != null) {
+ checkExpressionNode(md, nametable, rn.getReturnExpression());
+ }
+ }
+
+ private void checkSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode sbn) {
+ checkBlockNode(md, nametable, sbn.getBlockNode());
+ }
+
+ private void checkIfStatementNode(MethodDescriptor md, SymbolTable nametable, IfStatementNode isn) {
+ checkExpressionNode(md, nametable, isn.getCondition());
+ checkBlockNode(md, nametable, isn.getTrueBlock());
+ if (isn.getFalseBlock() != null)
+ checkBlockNode(md, nametable, isn.getFalseBlock());
+ }
+
+ private void checkSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
+ SwitchStatementNode ssn) {
+
+ checkExpressionNode(md, nametable, ssn.getCondition());
+
+ BlockNode sbn = ssn.getSwitchBody();
+ for (int i = 0; i < sbn.size(); i++) {
+ checkSwitchBlockNode(md, nametable, (SwitchBlockNode) sbn.get(i));
+ }
+ }
+
+ private void checkSwitchBlockNode(MethodDescriptor md, SymbolTable nametable, SwitchBlockNode sbn) {
+ checkBlockNode(md, nametable, sbn.getSwitchBlockStatement());
+ }
+
+ private void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
+ BlockExpressionNode ben) {
+ checkExpressionNode(md, nametable, ben.getExpression());
+ }
+
+ private void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en) {
+ switch (en.kind()) {
+ case Kind.AssignmentNode:
+ checkAssignmentNode(md, nametable, (AssignmentNode) en);
+ return;
+
+ case Kind.CastNode:
+ checkCastNode(md, nametable, (CastNode) en);
+ return;
+
+ case Kind.CreateObjectNode:
+ checkCreateObjectNode(md, nametable, (CreateObjectNode) en);
+ return;
+
+ case Kind.FieldAccessNode:
+ checkFieldAccessNode(md, nametable, (FieldAccessNode) en);
+ return;
+
+ case Kind.ArrayAccessNode:
+ checkArrayAccessNode(md, nametable, (ArrayAccessNode) en);
+ return;
+
+ // case Kind.LiteralNode:
+ // checkLiteralNode(md, nametable, (LiteralNode) en);
+ // return;
+
+ case Kind.MethodInvokeNode:
+ checkMethodInvokeNode(md, nametable, (MethodInvokeNode) en);
+ return;
+
+ case Kind.NameNode:
+ checkNameNode(md, nametable, (NameNode) en);
+ return;
+
+ case Kind.OpNode:
+ checkOpNode(md, nametable, (OpNode) en);
+ return;
+
+ case Kind.OffsetNode:
+ checkOffsetNode(md, nametable, (OffsetNode) en);
+ return;
+
+ case Kind.TertiaryNode:
+ checkTertiaryNode(md, nametable, (TertiaryNode) en);
+ return;
+
+ // case Kind.InstanceOfNode:
+ // checkInstanceOfNode(md, nametable, (InstanceOfNode) en);
+ // return;
+
+ // case Kind.ArrayInitializerNode:
+ // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en);
+ // return;
+
+ // case Kind.ClassTypeNode:
+ // checkClassTypeNode(md, nametable, (ClassTypeNode) ens);
+ // return;
+ }
+ throw new Error();
+ }
+
+ private void checkTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode en) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void checkOffsetNode(MethodDescriptor md, SymbolTable nametable, OffsetNode en) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode en) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void checkNameNode(MethodDescriptor md, SymbolTable nametable, NameNode en) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void checkMethodInvokeNode(MethodDescriptor md, SymbolTable nametable, MethodInvokeNode en) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void checkArrayAccessNode(MethodDescriptor md, SymbolTable nametable, ArrayAccessNode en) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable, FieldAccessNode fan) {
+
+ }
+
+ private void checkCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
+ CreateObjectNode con) {
+ TypeDescriptor[] tdarray = new TypeDescriptor[con.numArgs()];
+ for (int i = 0; i < con.numArgs(); i++) {
+ ExpressionNode en = con.getArg(i);
+ checkExpressionNode(md, nametable, en);
+ tdarray[i] = en.getType();
+ }
+
+ if ((con.getArrayInitializer() != null)) {
+ checkArrayInitializerNode(md, nametable, con.getArrayInitializer());
+ }
+
+ }
+
+ private void checkArrayInitializerNode(MethodDescriptor md, SymbolTable nametable,
+ ArrayInitializerNode arrayInitializer) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void checkCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn) {
+ ExpressionNode en = cn.getExpression();
+ checkExpressionNode(md, nametable, en);
+ }
+
+ private boolean checkNullifying(BlockStatementNode bsn) {
+
+ if (bsn.kind() == Kind.BlockExpressionNode) {
+ ExpressionNode en = ((BlockExpressionNode) bsn).getExpression();
+ if (en.kind() == Kind.AssignmentNode) {
+ AssignmentNode an = (AssignmentNode) en;
+
+ if (an.getSrc().getType().isNull() && an.getDest().printNode(0).equals(needToNullify)) {
+ needToNullify = null;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private void checkLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln) {
+ if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
+ checkExpressionNode(md, nametable, ln.getCondition());
+ checkBlockNode(md, nametable, ln.getBody());
+ } else {
+ // For loop case
+ /* Link in the initializer naming environment */
+ BlockNode bn = ln.getInitializer();
+ for (int i = 0; i < bn.size(); i++) {
+ BlockStatementNode bsn = bn.get(i);
+ checkBlockStatementNode(md, bn.getVarTable(), bsn);
+ }
+ // check the condition
+ checkExpressionNode(md, bn.getVarTable(), ln.getCondition());
+ checkBlockNode(md, bn.getVarTable(), ln.getBody());
+ checkBlockNode(md, bn.getVarTable(), ln.getUpdate());
+ }
+ }
+
+ private void checkAssignmentNode(Descriptor md, SymbolTable nametable, AssignmentNode an) {
+ needToNullify(an.getSrc());
+ }
+
+ private void checkDeclarationNode(Descriptor md, SymbolTable nametable, DeclarationNode dn) {
+ needToNullify(dn.getExpression());
+ }
+
+ private void needToNullify(ExpressionNode en) {
+
+ if (en != null && en.getType().isPtr() && !en.getType().isString()) {
+ if (en.kind() != Kind.CreateObjectNode && en.kind() != Kind.LiteralNode) {
+ if (en.kind() == Kind.CastNode) {
+ needToNullify = ((CastNode) en).getExpression().printNode(0);
+ } else {
+ needToNullify = en.printNode(0);
+ }
+ }
+ }
+
+ }
+
+}
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
*----------------------------------------------------------------------\r
*/\r
- \r
\r
/**\r
- * The <code>Decoder</code> class encapsulates the details of\r
- * decoding an MPEG audio frame. \r
+ * The <code>Decoder</code> class encapsulates the details of decoding an MPEG\r
+ * audio frame.\r
* \r
- * @author MDM \r
+ * @author MDM\r
* @version 0.0.7 12/12/99\r
- * @since 0.0.5\r
+ * @since 0.0.5\r
*/\r
@LATTICE("ST,DE<OUT,DE<FIL,DE<LA,O,EQ,PA,INIT,DE*")\r
-public class Decoder implements DecoderErrors\r
-{\r
- static private final Params DEFAULT_PARAMS = new Params();\r
- \r
- /**\r
- * The Bistream from which the MPEG audio frames are read.\r
- */\r
- @LOC("ST") private Bitstream stream;\r
- \r
- /**\r
- * The Obuffer instance that will receive the decoded\r
- * PCM samples.\r
- */\r
- @LOC("OUT") private Obuffer output;\r
- \r
- /**\r
- * Synthesis filter for the left channel.\r
- */\r
- @LOC("FIL") private SynthesisFilter filter1;\r
- \r
- /**\r
- * Sythesis filter for the right channel.\r
- */\r
- @LOC("FIL") private SynthesisFilter filter2; \r
- \r
- /**\r
- * The decoder used to decode layer III frames.\r
- */\r
- @LOC("DE") private LayerIIIDecoder l3decoder;\r
- @LOC("DE") private LayerIIDecoder l2decoder;\r
- @LOC("DE") private LayerIDecoder l1decoder;\r
- \r
- @LOC("O") private int outputFrequency;\r
- @LOC("O") private int outputChannels;\r
- \r
- @LOC("EQ") private Equalizer equalizer = new Equalizer();\r
- \r
- @LOC("PA") private Params params;\r
- \r
- @LOC("INIT") private boolean initialized;\r
- \r
- \r
- /**\r
- * Creates a new <code>Decoder</code> instance with default \r
- * parameters.\r
- */\r
- \r
- public Decoder()\r
- {\r
- this(null);\r
- }\r
-\r
- /**\r
- * Creates a new <code>Decoder</code> instance with default \r
- * parameters.\r
- * \r
- * @param params The <code>Params</code> instance that describes\r
- * the customizable aspects of the decoder. \r
- */\r
- public Decoder(Params params0)\r
- {\r
- if (params0==null)\r
- params0 = DEFAULT_PARAMS;\r
- \r
- params = params0;\r
- \r
- Equalizer eq = params.getInitialEqualizerSettings();\r
- if (eq!=null)\r
- {\r
- equalizer.setFrom(eq);\r
- }\r
- }\r
- \r
- static public Params getDefaultParams()\r
- {\r
- return (Params)DEFAULT_PARAMS.clone();\r
- }\r
- \r
- public void setEqualizer(Equalizer eq)\r
- {\r
- if (eq==null)\r
- eq = Equalizer.PASS_THRU_EQ;\r
- \r
- equalizer.setFrom(eq);\r
- \r
- float[] factors = equalizer.getBandFactors();\r
-\r
- if (filter1!=null)\r
- filter1.setEQ(factors);\r
- \r
- if (filter2!=null)\r
- filter2.setEQ(factors); \r
- }\r
- \r
- /**\r
- * Decodes one frame from an MPEG audio bitstream.\r
- * \r
- * @param header The header describing the frame to decode.\r
- * @param bitstream The bistream that provides the bits for te body of the frame. \r
- * \r
- * @return A SampleBuffer containing the decoded samples.\r
- */\r
- @LATTICE("O<DE,DE<TH,TH<IN,THISLOC=TH")\r
- @RETURNLOC("O")\r
- public Obuffer decodeFrame(@LOC("IN") Header header, @LOC("IN") Bitstream stream)\r
- throws DecoderException\r
- {\r
- // throw decoder initialization out of ssjava loop since it is invoked once\r
- // if (!initialized)\r
- // {\r
- // initialize(header,stream);\r
- // }\r
-\r
- @LOC("TH") int layer = header.layer();\r
-\r
- output.clear_buffer();\r
-\r
-// @LOC("DE,Decoder.DE") FrameDecoder decoder = retrieveDecoder(header, stream, layer); // return ceil=DELTA(TH)\r
-// decoder.decodeFrame();\r
-\r
- if(layer==3){\r
- if (l3decoder==null)\r
- {\r
- l3decoder = new LayerIIIDecoder(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS);\r
- } \r
- l3decoder.decodeFrame();\r
- }else if(layer==2){\r
- if (l2decoder==null)\r
- {\r
- l2decoder = new LayerIIDecoder();\r
- l2decoder.create(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
- }\r
- l2decoder.decodeFrame();\r
- }else{\r
- if (l1decoder==null)\r
- {\r
- l1decoder = new LayerIDecoder();\r
- l1decoder.create(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
- }\r
- l1decoder.decodeFrame();\r
- }\r
-\r
- output.write_buffer(1);\r
-\r
- return output; \r
- }\r
- \r
- /**\r
- * Changes the output buffer. This will take effect the next time\r
- * decodeFrame() is called. \r
- */\r
- public void setOutputBuffer(Obuffer out)\r
- {\r
- output = out;\r
- }\r
- \r
- /**\r
- * Retrieves the sample frequency of the PCM samples output\r
- * by this decoder. This typically corresponds to the sample\r
- * rate encoded in the MPEG audio stream.\r
- * \r
- * @param the sample rate (in Hz) of the samples written to the\r
- * output buffer when decoding. \r
- */\r
- public int getOutputFrequency()\r
- {\r
- return outputFrequency;\r
- }\r
- \r
- /**\r
- * Retrieves the number of channels of PCM samples output by\r
- * this decoder. This usually corresponds to the number of\r
- * channels in the MPEG audio stream, although it may differ.\r
- * \r
- * @return The number of output channels in the decoded samples: 1 \r
- * for mono, or 2 for stereo.\r
- * \r
- */\r
- public int getOutputChannels()\r
- {\r
- return outputChannels; \r
- }\r
- \r
- /**\r
- * Retrieves the maximum number of samples that will be written to\r
- * the output buffer when one frame is decoded. This can be used to\r
- * help calculate the size of other buffers whose size is based upon \r
- * the number of samples written to the output buffer. NB: this is\r
- * an upper bound and fewer samples may actually be written, depending\r
- * upon the sample rate and number of channels.\r
- * \r
- * @return The maximum number of samples that are written to the \r
- * output buffer when decoding a single frame of MPEG audio.\r
- */\r
- public int getOutputBlockSize()\r
- {\r
- return Obuffer.OBUFFERSIZE;\r
- }\r
- \r
- \r
- protected DecoderException newDecoderException(int errorcode)\r
- {\r
- return new DecoderException(errorcode, null);\r
- }\r
- \r
- protected DecoderException newDecoderException(int errorcode, Throwable throwable)\r
- {\r
- return new DecoderException(errorcode, throwable);\r
- }\r
- \r
- @LATTICE("IN,TH,THISLOC=TH")\r
- @RETURNLOC("TH")\r
- protected FrameDecoder retrieveDecoder(@LOC("IN") Header header, @LOC("IN") Bitstream stream, @LOC("IN") int layer)\r
- throws DecoderException\r
- {\r
-// @LOC("DE") FrameDecoder decoder = null;\r
- \r
- // REVIEW: allow channel output selection type\r
- // (LEFT, RIGHT, BOTH, DOWNMIX)\r
- switch (layer)\r
- {\r
- case 3:\r
- if (l3decoder==null)\r
- {\r
- l3decoder = new LayerIIIDecoder(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS);\r
- } \r
- \r
- return l3decoder;\r
-// decoder = l3decoder;\r
- break;\r
- case 2:\r
- if (l2decoder==null)\r
- {\r
- l2decoder = new LayerIIDecoder();\r
- l2decoder.create(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
- }\r
- return l2decoder;\r
-// decoder = l2decoder;\r
- break;\r
- case 1:\r
- if (l1decoder==null)\r
- {\r
- l1decoder = new LayerIDecoder();\r
- l1decoder.create(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
- }\r
- return l1decoder;\r
-// decoder = l1decoder;\r
- break;\r
- }\r
-// \r
-// if (decoder==null)\r
-// {\r
-// throw newDecoderException(UNSUPPORTED_LAYER, null);\r
-// }\r
-// \r
-// return decoder;\r
- }\r
- \r
- public void initialize(Header header, Bitstream stream)\r
- throws DecoderException\r
- {\r
- \r
- // REVIEW: allow customizable scale factor\r
- float scalefactor = 32700.0f;\r
- \r
- int mode = header.mode();\r
- int layer = header.layer();\r
- int channels = mode==Header.SINGLE_CHANNEL ? 1 : 2;\r
-\r
- \r
- // set up output buffer if not set up by client.\r
- if (output==null)\r
- output = new SampleBuffer(header.frequency(), channels);\r
- \r
- float[] factors = equalizer.getBandFactors();\r
- filter1 = new SynthesisFilter(0, scalefactor, factors);\r
- \r
- // REVIEW: allow mono output for stereo\r
- if (channels==2) \r
- filter2 = new SynthesisFilter(1, scalefactor, factors);\r
-\r
- outputChannels = channels;\r
- outputFrequency = header.frequency();\r
-\r
- l3decoder = new LayerIIIDecoder(stream, header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS);\r
- l2decoder = new LayerIIDecoder();\r
- l2decoder.create(stream, header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS);\r
-\r
- l1decoder = new LayerIDecoder();\r
- l1decoder.create(stream,header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
-\r
- initialized = true;\r
- }\r
- \r
- /**\r
- * The <code>Params</code> class presents the customizable\r
- * aspects of the decoder. \r
- * <p>\r
- * Instances of this class are not thread safe. \r
- */\r
- public static class Params implements Cloneable\r
- {\r
- private OutputChannels outputChannels = OutputChannels.BOTH;\r
- \r
- private Equalizer equalizer = new Equalizer();\r
- \r
- public Params()\r
- { \r
- }\r
- \r
- public Object clone()\r
- {\r
- //TODO: need to have better clone method\r
- Params clone=new Params();\r
- clone.outputChannels=outputChannels;\r
- clone.equalizer=equalizer;\r
- return clone;\r
-// try\r
-// {\r
-// return super.clone();\r
-// }\r
-// catch (CloneNotSupportedException ex)\r
-// { \r
-// throw new InternalError(this+": "+ex);\r
-// }\r
- }\r
- \r
- public void setOutputChannels(OutputChannels out)\r
- {\r
- if (out==null)\r
- throw new NullPointerException("out");\r
- \r
- outputChannels = out;\r
- }\r
- \r
- public OutputChannels getOutputChannels()\r
- {\r
- return outputChannels;\r
- }\r
- \r
- /**\r
- * Retrieves the equalizer settings that the decoder's equalizer\r
- * will be initialized from.\r
- * <p>\r
- * The <code>Equalizer</code> instance returned \r
- * cannot be changed in real time to affect the \r
- * decoder output as it is used only to initialize the decoders\r
- * EQ settings. To affect the decoder's output in realtime,\r
- * use the Equalizer returned from the getEqualizer() method on\r
- * the decoder. \r
- * \r
- * @return The <code>Equalizer</code> used to initialize the\r
- * EQ settings of the decoder. \r
- */\r
- public Equalizer getInitialEqualizerSettings()\r
- {\r
- return equalizer; \r
- }\r
- \r
- };\r
-}\r
+public class Decoder implements DecoderErrors {\r
+ static private final Params DEFAULT_PARAMS = new Params();\r
+\r
+ /**\r
+ * The Bistream from which the MPEG audio frames are read.\r
+ */\r
+ @LOC("ST")\r
+ private Bitstream stream;\r
+\r
+ /**\r
+ * The Obuffer instance that will receive the decoded PCM samples.\r
+ */\r
+ @LOC("OUT")\r
+ private Obuffer output;\r
+\r
+ /**\r
+ * Synthesis filter for the left channel.\r
+ */\r
+ @LOC("FIL")\r
+ private SynthesisFilter filter1;\r
+\r
+ /**\r
+ * Sythesis filter for the right channel.\r
+ */\r
+ @LOC("FIL")\r
+ private SynthesisFilter filter2;\r
+\r
+ /**\r
+ * The decoder used to decode layer III frames.\r
+ */\r
+ @LOC("DE")\r
+ private LayerIIIDecoder l3decoder;\r
+ @LOC("DE")\r
+ private LayerIIDecoder l2decoder;\r
+ @LOC("DE")\r
+ private LayerIDecoder l1decoder;\r
+\r
+ @LOC("O")\r
+ private int outputFrequency;\r
+ @LOC("O")\r
+ private int outputChannels;\r
+\r
+ @LOC("EQ")\r
+ private Equalizer equalizer = new Equalizer();\r
+\r
+ @LOC("PA")\r
+ private Params params;\r
+\r
+ @LOC("INIT")\r
+ private boolean initialized;\r
+\r
+ /**\r
+ * Creates a new <code>Decoder</code> instance with default parameters.\r
+ */\r
+\r
+ public Decoder() {\r
+ this(null);\r
+ }\r
+\r
+ /**\r
+ * Creates a new <code>Decoder</code> instance with default parameters.\r
+ * \r
+ * @param params\r
+ * The <code>Params</code> instance that describes the customizable\r
+ * aspects of the decoder.\r
+ */\r
+ public Decoder(Params params0) {\r
+ if (params0 == null)\r
+ params0 = DEFAULT_PARAMS;\r
+\r
+ params = params0;\r
+\r
+ Equalizer eq = params.getInitialEqualizerSettings();\r
+ if (eq != null) {\r
+ equalizer.setFrom(eq);\r
+ }\r
+ }\r
+\r
+ static public Params getDefaultParams() {\r
+ return (Params) DEFAULT_PARAMS.clone();\r
+ }\r
+\r
+ public void setEqualizer(Equalizer eq) {\r
+ if (eq == null)\r
+ eq = Equalizer.PASS_THRU_EQ;\r
+\r
+ equalizer.setFrom(eq);\r
+\r
+ float[] factors = equalizer.getBandFactors();\r
+\r
+ if (filter1 != null)\r
+ filter1.setEQ(factors);\r
+\r
+ if (filter2 != null)\r
+ filter2.setEQ(factors);\r
+ }\r
+\r
+ /**\r
+ * Decodes one frame from an MPEG audio bitstream.\r
+ * \r
+ * @param header\r
+ * The header describing the frame to decode.\r
+ * @param bitstream\r
+ * The bistream that provides the bits for te body of the frame.\r
+ * \r
+ * @return A SampleBuffer containing the decoded samples.\r
+ */\r
+ @LATTICE("O<DE,DE<TH,TH<IN,THISLOC=TH")\r
+ @RETURNLOC("O")\r
+ public Obuffer decodeFrame(@LOC("IN") Header header, @LOC("IN") Bitstream stream)\r
+ throws DecoderException {\r
+\r
+ if (!initialized) {\r
+ initialize(header);\r
+ }\r
+\r
+ @LOC("TH") int layer = header.layer();\r
+\r
+ output.clear_buffer();\r
+\r
+ @LOC("DE,Decoder.DE") FrameDecoder decoder = retrieveDecoder(header, stream, layer); // return\r
+ // ceil=DELTA(TH)\r
+ decoder.decodeFrame();\r
+\r
+ // if (layer == 3) {\r
+ // if (l3decoder == null) {\r
+ // l3decoder =\r
+ // new LayerIIIDecoder(stream, header, filter1, filter2, output,\r
+ // OutputChannels.BOTH_CHANNELS);\r
+ // }\r
+ // l3decoder.decodeFrame();\r
+ // } else if (layer == 2) {\r
+ // if (l2decoder == null) {\r
+ // l2decoder = new LayerIIDecoder();\r
+ // l2decoder.create(stream, header, filter1, filter2, output,\r
+ // OutputChannels.BOTH_CHANNELS);\r
+ // }\r
+ // l2decoder.decodeFrame();\r
+ // } else {\r
+ // if (l1decoder == null) {\r
+ // l1decoder = new LayerIDecoder();\r
+ // l1decoder.create(stream, header, filter1, filter2, output,\r
+ // OutputChannels.BOTH_CHANNELS);\r
+ // }\r
+ // l1decoder.decodeFrame();\r
+ // }\r
+\r
+ output.write_buffer(1);\r
\r
+ return output;\r
+ }\r
+\r
+ /**\r
+ * Changes the output buffer. This will take effect the next time\r
+ * decodeFrame() is called.\r
+ */\r
+ public void setOutputBuffer(Obuffer out) {\r
+ output = out;\r
+ }\r
+\r
+ /**\r
+ * Retrieves the sample frequency of the PCM samples output by this decoder.\r
+ * This typically corresponds to the sample rate encoded in the MPEG audio\r
+ * stream.\r
+ * \r
+ * @param the\r
+ * sample rate (in Hz) of the samples written to the output buffer\r
+ * when decoding.\r
+ */\r
+ public int getOutputFrequency() {\r
+ return outputFrequency;\r
+ }\r
+\r
+ /**\r
+ * Retrieves the number of channels of PCM samples output by this decoder.\r
+ * This usually corresponds to the number of channels in the MPEG audio\r
+ * stream, although it may differ.\r
+ * \r
+ * @return The number of output channels in the decoded samples: 1 for mono,\r
+ * or 2 for stereo.\r
+ * \r
+ */\r
+ public int getOutputChannels() {\r
+ return outputChannels;\r
+ }\r
+\r
+ /**\r
+ * Retrieves the maximum number of samples that will be written to the output\r
+ * buffer when one frame is decoded. This can be used to help calculate the\r
+ * size of other buffers whose size is based upon the number of samples\r
+ * written to the output buffer. NB: this is an upper bound and fewer samples\r
+ * may actually be written, depending upon the sample rate and number of\r
+ * channels.\r
+ * \r
+ * @return The maximum number of samples that are written to the output buffer\r
+ * when decoding a single frame of MPEG audio.\r
+ */\r
+ public int getOutputBlockSize() {\r
+ return Obuffer.OBUFFERSIZE;\r
+ }\r
+\r
+ protected DecoderException newDecoderException(int errorcode) {\r
+ return new DecoderException(errorcode, null);\r
+ }\r
+\r
+ protected DecoderException newDecoderException(int errorcode, Throwable throwable) {\r
+ return new DecoderException(errorcode, throwable);\r
+ }\r
+\r
+ @LATTICE("IN,TH,THISLOC=TH")\r
+ @RETURNLOC("TH")\r
+ protected FrameDecoder retrieveDecoder(@LOC("IN") Header header, @LOC("IN") Bitstream stream,\r
+ @LOC("IN") int layer) throws DecoderException {\r
+ // @LOC("DE") FrameDecoder decoder = null;\r
+\r
+ // REVIEW: allow channel output selection type\r
+ // (LEFT, RIGHT, BOTH, DOWNMIX)\r
+ switch (layer) {\r
+ case 3:\r
+ if (l3decoder == null) {\r
+ l3decoder =\r
+ new LayerIIIDecoder(stream, header, filter1, filter2, output,\r
+ OutputChannels.BOTH_CHANNELS);\r
+ }\r
+\r
+ return l3decoder;\r
+ // decoder = l3decoder;\r
+ break;\r
+ case 2:\r
+ if (l2decoder == null) {\r
+ l2decoder = new LayerIIDecoder();\r
+ l2decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
+ }\r
+ return l2decoder;\r
+ // decoder = l2decoder;\r
+ break;\r
+ case 1:\r
+ if (l1decoder == null) {\r
+ l1decoder = new LayerIDecoder();\r
+ l1decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
+ }\r
+ return l1decoder;\r
+ // decoder = l1decoder;\r
+ break;\r
+ }\r
+ //\r
+ // if (decoder==null)\r
+ // {\r
+ // throw newDecoderException(UNSUPPORTED_LAYER, null);\r
+ // }\r
+ //\r
+ // return decoder;\r
+ }\r
+\r
+ public void initialize(Header header) throws DecoderException {\r
+\r
+ // REVIEW: allow customizable scale factor\r
+ float scalefactor = 32700.0f;\r
+\r
+ int mode = header.mode();\r
+ int layer = header.layer();\r
+ int channels = mode == Header.SINGLE_CHANNEL ? 1 : 2;\r
+\r
+ // set up output buffer if not set up by client.\r
+ if (output == null)\r
+ output = new SampleBuffer(header.frequency(), channels);\r
+\r
+ float[] factors = equalizer.getBandFactors();\r
+ filter1 = new SynthesisFilter(0, scalefactor, factors);\r
+\r
+ // REVIEW: allow mono output for stereo\r
+ if (channels == 2)\r
+ filter2 = new SynthesisFilter(1, scalefactor, factors);\r
+\r
+ outputChannels = channels;\r
+ outputFrequency = header.frequency();\r
+\r
+ initialized = true;\r
+ }\r
+\r
+ /**\r
+ * The <code>Params</code> class presents the customizable aspects of the\r
+ * decoder.\r
+ * <p>\r
+ * Instances of this class are not thread safe.\r
+ */\r
+ public static class Params implements Cloneable {\r
+ private OutputChannels outputChannels = OutputChannels.BOTH;\r
+\r
+ private Equalizer equalizer = new Equalizer();\r
+\r
+ public Params() {\r
+ }\r
+\r
+ public Object clone() {\r
+ // TODO: need to have better clone method\r
+ Params clone = new Params();\r
+ clone.outputChannels = outputChannels;\r
+ clone.equalizer = equalizer;\r
+ return clone;\r
+ // try\r
+ // {\r
+ // return super.clone();\r
+ // }\r
+ // catch (CloneNotSupportedException ex)\r
+ // {\r
+ // throw new InternalError(this+": "+ex);\r
+ // }\r
+ }\r
+\r
+ public void setOutputChannels(OutputChannels out) {\r
+ if (out == null)\r
+ throw new NullPointerException("out");\r
+\r
+ outputChannels = out;\r
+ }\r
+\r
+ public OutputChannels getOutputChannels() {\r
+ return outputChannels;\r
+ }\r
+\r
+ /**\r
+ * Retrieves the equalizer settings that the decoder's equalizer will be\r
+ * initialized from.\r
+ * <p>\r
+ * The <code>Equalizer</code> instance returned cannot be changed in real\r
+ * time to affect the decoder output as it is used only to initialize the\r
+ * decoders EQ settings. To affect the decoder's output in realtime, use the\r
+ * Equalizer returned from the getEqualizer() method on the decoder.\r
+ * \r
+ * @return The <code>Equalizer</code> used to initialize the EQ settings of\r
+ * the decoder.\r
+ */\r
+ public Equalizer getInitialEqualizerSettings() {\r
+ return equalizer;\r
+ }\r
+\r
+ };\r
+}\r
*/\r
@LATTICE("HI<HNS,HNS<H,C<H,NS<FS,FS<H,FS<HV,H<SYNC,HV<SYNC,HV<T,SYNC*,HV*,FS*,HI*")\r
@METHODDEFAULT("OUT<V,V<THIS,THIS<SH,SH<IN,SH*,THISLOC=THIS,GLOBALLOC=IN")\r
-public final class Header\r
-{\r
- @LOC("T") public static final int[][] frequencies =\r
- {{22050, 24000, 16000, 1},\r
- {44100, 48000, 32000, 1},\r
- {11025, 12000, 8000, 1}}; // SZD: MPEG25\r
-\r
- /**\r
- * Constant for MPEG-2 LSF version\r
- */\r
- @LOC("T") public static final int MPEG2_LSF = 0;\r
- @LOC("T") public static final int MPEG25_LSF = 2; // SZD\r
-\r
- /**\r
- * Constant for MPEG-1 version\r
- */\r
- @LOC("T") public static final int MPEG1 = 1;\r
-\r
- @LOC("T") public static final int STEREO = 0;\r
- @LOC("T") public static final int JOINT_STEREO = 1;\r
- @LOC("T") public static final int DUAL_CHANNEL = 2;\r
- @LOC("T") public static final int SINGLE_CHANNEL = 3;\r
- @LOC("T") public static final int FOURTYFOUR_POINT_ONE = 0;\r
- @LOC("T") public static final int FOURTYEIGHT=1;\r
- @LOC("T") public static final int THIRTYTWO=2;\r
-\r
- @LOC("H") private int h_layer;\r
- @LOC("H") private int h_protection_bit;\r
- @LOC("H") private int h_bitrate_index;\r
- @LOC("H") private int h_padding_bit;\r
- @LOC("H") private int h_mode_extension;\r
- @LOC("HV") private int h_version;\r
- @LOC("H") private int h_mode;\r
- @LOC("H") private int h_sample_frequency;\r
- @LOC("HNS") private int h_number_of_subbands;\r
- @LOC("HI") private int h_intensity_stereo_bound;\r
- @LOC("H") private boolean h_copyright;\r
- @LOC("H") private boolean h_original;\r
- // VBR support added by E.B\r
- @LOC("T") private double[] h_vbr_time_per_frame = {-1.0, 384.0, 1152.0, 1152.0};\r
- @LOC("T") private boolean h_vbr;\r
- @LOC("T") private int h_vbr_frames;\r
- @LOC("T") private int h_vbr_scale;\r
- @LOC("T") private int h_vbr_bytes;\r
- @LOC("T") private byte[] h_vbr_toc;\r
- \r
- @LOC("SYNC") private byte syncmode = Bitstream.INITIAL_SYNC;\r
- @LOC("C") private Crc16 crc;\r
-\r
- @LOC("C") public short checksum;\r
- @LOC("FS") public int framesize;\r
- @LOC("NS") public int nSlots;\r
-\r
- @LOC("T") private int _headerstring = -1; // E.B\r
-\r
- Header()\r
- {\r
- }\r
- public String toString()\r
- {\r
- StringBuffer buffer = new StringBuffer(200);\r
- buffer.append("Layer ");\r
- buffer.append(layer_string());\r
- buffer.append(" frame ");\r
- buffer.append(mode_string());\r
- buffer.append(' ');\r
- buffer.append(version_string());\r
- if (!checksums())\r
- buffer.append(" no");\r
- buffer.append(" checksums");\r
- buffer.append(' ');\r
- buffer.append(sample_frequency_string());\r
- buffer.append(',');\r
- buffer.append(' ');\r
- buffer.append(bitrate_string());\r
-\r
- String s = buffer.toString();\r
- return s;\r
- }\r
-\r
- /**\r
- * Read a 32-bit header from the bitstream.\r
- */\r
- void read_header(Bitstream stream, Crc16[] crcp) throws BitstreamException\r
- {\r
- int headerstring;\r
- int channel_bitrate;\r
- boolean sync = false;\r
- do\r
- {\r
- headerstring = stream.syncHeader(syncmode);\r
- _headerstring = headerstring; // E.B\r
- if (syncmode == Bitstream.INITIAL_SYNC)\r
- {\r
- h_version = ((headerstring >>> 19) & 1);\r
- if (((headerstring >>> 20) & 1) == 0) // SZD: MPEG2.5 detection\r
- if (h_version == MPEG2_LSF)\r
- h_version = MPEG25_LSF;\r
- else\r
- throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);\r
- if ((h_sample_frequency = ((headerstring >>> 10) & 3)) == 3)\r
- {\r
- throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);\r
- }\r
- }\r
- h_layer = 4 - (headerstring >>> 17) & 3;\r
- h_protection_bit = (headerstring >>> 16) & 1;\r
- h_bitrate_index = (headerstring >>> 12) & 0xF;\r
- h_padding_bit = (headerstring >>> 9) & 1;\r
- h_mode = ((headerstring >>> 6) & 3);\r
- h_mode_extension = (headerstring >>> 4) & 3;\r
- if (h_mode == JOINT_STEREO)\r
- h_intensity_stereo_bound = (h_mode_extension << 2) + 4;\r
- else\r
- h_intensity_stereo_bound = 0; // should never be used\r
- if (((headerstring >>> 3) & 1) == 1)\r
- h_copyright = true;\r
- if (((headerstring >>> 2) & 1) == 1)\r
- h_original = true;\r
- // calculate number of subbands:\r
- if (h_layer == 1)\r
- h_number_of_subbands = 32;\r
- else\r
- {\r
- channel_bitrate = h_bitrate_index;\r
- // calculate bitrate per channel:\r
- if (h_mode != SINGLE_CHANNEL)\r
- if (channel_bitrate == 4)\r
- channel_bitrate = 1;\r
- else\r
- channel_bitrate -= 4;\r
- if ((channel_bitrate == 1) || (channel_bitrate == 2))\r
- if (h_sample_frequency == THIRTYTWO)\r
- h_number_of_subbands = 12;\r
- else\r
- h_number_of_subbands = 8;\r
- else if ((h_sample_frequency == FOURTYEIGHT) || ((channel_bitrate >= 3) && (channel_bitrate <= 5)))\r
- h_number_of_subbands = 27;\r
- else\r
- h_number_of_subbands = 30;\r
- }\r
- if (h_intensity_stereo_bound > h_number_of_subbands)\r
- h_intensity_stereo_bound = h_number_of_subbands;\r
- // calculate framesize and nSlots\r
- calculate_framesize();\r
- // read framedata:\r
- int framesizeloaded = stream.read_frame_data(framesize);\r
- if ((framesize >=0) && (framesizeloaded != framesize))\r
- {\r
- // Data loaded does not match to expected framesize,\r
- // it might be an ID3v1 TAG. (Fix 11/17/04).\r
- throw stream.newBitstreamException(Bitstream.INVALIDFRAME);\r
- }\r
- if (stream.isSyncCurrentPosition(syncmode))\r
- {\r
- if (syncmode == Bitstream.INITIAL_SYNC)\r
- {\r
- syncmode = Bitstream.STRICT_SYNC;\r
- stream.set_syncword(headerstring & 0xFFF80CC0);\r
- }\r
- sync = true;\r
- }\r
- else\r
- {\r
- stream.unreadFrame();\r
- }\r
- }\r
- while (!sync);\r
- stream.parse_frame();\r
- if (h_protection_bit == 0)\r
- {\r
- // frame contains a crc checksum\r
- checksum = (short) stream.get_bits(16);\r
- if (crc == null)\r
- crc = new Crc16();\r
- crc.add_bits(headerstring, 16);\r
- crcp[0] = crc;\r
- }\r
- else\r
- crcp[0] = null;\r
- if (h_sample_frequency == FOURTYFOUR_POINT_ONE)\r
- {\r
- /*\r
- if (offset == null)\r
- {\r
- int max = max_number_of_frames(stream);\r
- offset = new int[max];\r
- for(int i=0; i<max; i++) offset[i] = 0;\r
- }\r
- // E.B : Investigate more\r
- int cf = stream.current_frame();\r
- int lf = stream.last_frame();\r
- if ((cf > 0) && (cf == lf))\r
- {\r
- offset[cf] = offset[cf-1] + h_padding_bit;\r
- }\r
- else\r
- {\r
- offset[0] = h_padding_bit;\r
- }\r
- */\r
- }\r
- }\r
-\r
- /**\r
- * Parse frame to extract optionnal VBR frame.\r
- * @param firstframe\r
- * @author E.B (javalayer@javazoom.net)\r
- */\r
- void parseVBR(byte[] firstframe) throws BitstreamException\r
- {\r
- // Trying Xing header.\r
- String xing = "Xing";\r
- byte tmp[] = new byte[4];\r
- int offset = 0;\r
- // Compute "Xing" offset depending on MPEG version and channels.\r
- if (h_version == MPEG1) \r
- {\r
- if (h_mode == SINGLE_CHANNEL) offset=21-4;\r
- else offset=36-4;\r
- } \r
- else \r
- {\r
- if (h_mode == SINGLE_CHANNEL) offset=13-4;\r
- else offset = 21-4; \r
- }\r
- try\r
- {\r
- System.arraycopy(firstframe, offset, tmp, 0, 4);\r
- // Is "Xing" ?\r
- if (xing.equals(new String(tmp)))\r
- {\r
- //Yes.\r
- h_vbr = true;\r
- h_vbr_frames = -1;\r
- h_vbr_bytes = -1;\r
- h_vbr_scale = -1;\r
- h_vbr_toc = new byte[100];\r
- \r
- int length = 4;\r
- // Read flags.\r
- byte flags[] = new byte[4];\r
- System.arraycopy(firstframe, offset + length, flags, 0, flags.length);\r
- length += flags.length;\r
- // Read number of frames (if available).\r
- if ((flags[3] & (byte) (1 << 0)) != 0)\r
- {\r
- System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
- h_vbr_frames = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;\r
- length += 4; \r
- }\r
- // Read size (if available).\r
- if ((flags[3] & (byte) (1 << 1)) != 0)\r
- {\r
- System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
- h_vbr_bytes = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;\r
- length += 4; \r
- }\r
- // Read TOC (if available).\r
- if ((flags[3] & (byte) (1 << 2)) != 0)\r
- {\r
- System.arraycopy(firstframe, offset + length, h_vbr_toc, 0, h_vbr_toc.length);\r
- length += h_vbr_toc.length; \r
- }\r
- // Read scale (if available).\r
- if ((flags[3] & (byte) (1 << 3)) != 0)\r
- {\r
- System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
- h_vbr_scale = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;\r
- length += 4; \r
- }\r
- //System.out.println("VBR:"+xing+" Frames:"+ h_vbr_frames +" Size:"+h_vbr_bytes); \r
- } \r
- }\r
- catch (ArrayIndexOutOfBoundsException e)\r
- {\r
- throw new BitstreamException("XingVBRHeader Corrupted",e);\r
- }\r
- \r
- // Trying VBRI header. \r
- String vbri = "VBRI";\r
- offset = 36-4;\r
- try\r
- {\r
- System.arraycopy(firstframe, offset, tmp, 0, 4);\r
- // Is "VBRI" ?\r
- if (vbri.equals(new String(tmp)))\r
- {\r
- //Yes.\r
- h_vbr = true;\r
- h_vbr_frames = -1;\r
- h_vbr_bytes = -1;\r
- h_vbr_scale = -1;\r
- h_vbr_toc = new byte[100];\r
- // Bytes. \r
- int length = 4 + 6;\r
- System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
- h_vbr_bytes = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;\r
- length += 4; \r
- // Frames. \r
- System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
- h_vbr_frames = (tmp[0] << 24)&0xFF000000 | (tmp[1] << 16)&0x00FF0000 | (tmp[2] << 8)&0x0000FF00 | tmp[3]&0x000000FF;\r
- length += 4; \r
- //System.out.println("VBR:"+vbri+" Frames:"+ h_vbr_frames +" Size:"+h_vbr_bytes);\r
- // TOC\r
- // TODO \r
- }\r
- }\r
- catch (ArrayIndexOutOfBoundsException e)\r
- {\r
- throw new BitstreamException("VBRIVBRHeader Corrupted",e);\r
- }\r
- }\r
- \r
- // Functions to query header contents:\r
- /**\r
- * Returns version.\r
- */\r
- @RETURNLOC("OUT")\r
- public int version() { return h_version; }\r
-\r
- /**\r
- * Returns Layer ID.\r
- */\r
- @RETURNLOC("OUT")\r
- public int layer() { return h_layer; }\r
-\r
- /**\r
- * Returns bitrate index.\r
- */\r
- @RETURNLOC("OUT")\r
- public int bitrate_index() { return h_bitrate_index; }\r
-\r
- /**\r
- * Returns Sample Frequency.\r
- */\r
- public int sample_frequency() { return h_sample_frequency; }\r
-\r
- /**\r
- * Returns Frequency.\r
- */\r
- public int frequency() {return frequencies[h_version][h_sample_frequency];}\r
-\r
- /**\r
- * Returns Mode.\r
- */\r
- @RETURNLOC("OUT")\r
- public int mode() { return h_mode; }\r
-\r
- /**\r
- * Returns Protection bit.\r
- */\r
- public boolean checksums()\r
- {\r
- if (h_protection_bit == 0) return true;\r
- else return false;\r
- }\r
-\r
- /**\r
- * Returns Copyright.\r
- */\r
- public boolean copyright() { return h_copyright; }\r
-\r
- /**\r
- * Returns Original.\r
- */\r
- public boolean original() { return h_original; }\r
-\r
- /**\r
- * Return VBR.\r
- * @return true if VBR header is found\r
- */\r
- public boolean vbr() { return h_vbr; }\r
-\r
- /**\r
- * Return VBR scale.\r
- * @return scale of -1 if not available\r
- */\r
- public int vbr_scale() { return h_vbr_scale; }\r
-\r
- /**\r
- * Return VBR TOC.\r
- * @return vbr toc ot null if not available\r
- */\r
- public byte[] vbr_toc() { return h_vbr_toc; }\r
-\r
- /**\r
- * Returns Checksum flag.\r
- * Compares computed checksum with stream checksum.\r
- */\r
- @RETURNLOC("OUT")\r
- public boolean checksum_ok () { return (checksum == crc.checksum()); }\r
-\r
- // Seeking and layer III stuff\r
- /**\r
- * Returns Layer III Padding bit.\r
- */\r
- public boolean padding()\r
- {\r
- if (h_padding_bit == 0) return false;\r
- else return true;\r
- }\r
-\r
- /**\r
- * Returns Slots.\r
- */\r
- @RETURNLOC("OUT")\r
- public int slots() { return nSlots; }\r
-\r
- /**\r
- * Returns Mode Extension.\r
- */\r
- @RETURNLOC("OUT")\r
- public int mode_extension() { return h_mode_extension; }\r
-\r
- // E.B -> private to public\r
- @LOC("T") public static final int bitrates[][][] = {\r
- {{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,\r
- 112000, 128000, 144000, 160000, 176000, 192000 ,224000, 256000, 0},\r
- {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,\r
- 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0},\r
- {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,\r
- 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}},\r
-\r
- {{0 /*free format*/, 32000, 64000, 96000, 128000, 160000, 192000,\r
- 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000, 0},\r
- {0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,\r
- 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, 0},\r
- {0 /*free format*/, 32000, 40000, 48000, 56000, 64000, 80000,\r
- 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 0}},\r
- // SZD: MPEG2.5\r
- {{0 /*free format*/, 32000, 48000, 56000, 64000, 80000, 96000,\r
- 112000, 128000, 144000, 160000, 176000, 192000 ,224000, 256000, 0},\r
- {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,\r
- 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0},\r
- {0 /*free format*/, 8000, 16000, 24000, 32000, 40000, 48000,\r
- 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0}},\r
-\r
- };\r
-\r
- // E.B -> private to public\r
- /**\r
- * Calculate Frame size.\r
- * Calculates framesize in bytes excluding header size.\r
- */\r
- public int calculate_framesize()\r
- {\r
-\r
- if (h_layer == 1)\r
- {\r
- framesize = (12 * bitrates[h_version][0][h_bitrate_index]) /\r
- frequencies[h_version][h_sample_frequency];\r
- if (h_padding_bit != 0 ) framesize++;\r
- framesize <<= 2; // one slot is 4 bytes long\r
- nSlots = 0;\r
- }\r
- else\r
- {\r
- framesize = (144 * bitrates[h_version][h_layer - 1][h_bitrate_index]) /\r
- frequencies[h_version][h_sample_frequency];\r
- if (h_version == MPEG2_LSF || h_version == MPEG25_LSF) framesize >>= 1; // SZD\r
- if (h_padding_bit != 0) framesize++;\r
- // Layer III slots\r
- if (h_layer == 3)\r
- {\r
- if (h_version == MPEG1)\r
- {\r
- nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 17 : 32) // side info size\r
- - ((h_protection_bit!=0) ? 0 : 2) // CRC size\r
- - 4; // header size\r
- }\r
- else\r
- { // MPEG-2 LSF, SZD: MPEG-2.5 LSF\r
- nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 9 : 17) // side info size\r
- - ((h_protection_bit!=0) ? 0 : 2) // CRC size\r
- - 4; // header size\r
- }\r
- }\r
- else\r
- {\r
- nSlots = 0;\r
- }\r
- }\r
- framesize -= 4; // subtract header size\r
- return framesize;\r
- }\r
-\r
- /**\r
- * Returns the maximum number of frames in the stream.\r
- * @param streamsize\r
- * @return number of frames\r
- */\r
- public int max_number_of_frames(int streamsize) // E.B\r
- {\r
- if (h_vbr == true) return h_vbr_frames;\r
- else\r
- {\r
- if ((framesize + 4 - h_padding_bit) == 0) return 0;\r
- else return(streamsize / (framesize + 4 - h_padding_bit));\r
- }\r
- }\r
-\r
- /**\r
- * Returns the maximum number of frames in the stream.\r
- * @param streamsize\r
- * @return number of frames\r
- */\r
- public int min_number_of_frames(int streamsize) // E.B\r
- {\r
- if (h_vbr == true) return h_vbr_frames;\r
- else\r
- {\r
- if ((framesize + 5 - h_padding_bit) == 0) return 0;\r
- else return(streamsize / (framesize + 5 - h_padding_bit));\r
- }\r
- }\r
-\r
-\r
- /**\r
- * Returns ms/frame.\r
- * @return milliseconds per frame\r
- */\r
- public float ms_per_frame() // E.B\r
- {\r
- if (h_vbr == true)\r
- { \r
- double tpf = h_vbr_time_per_frame[layer()] / frequency();\r
- if ((h_version == MPEG2_LSF) || (h_version == MPEG25_LSF)) tpf /= 2;\r
- return ((float) (tpf * 1000));\r
- }\r
- else\r
- {\r
- float ms_per_frame_array[][] = {{8.707483f, 8.0f, 12.0f},\r
- {26.12245f, 24.0f, 36.0f},\r
- {26.12245f, 24.0f, 36.0f}};\r
- return(ms_per_frame_array[h_layer-1][h_sample_frequency]);\r
- }\r
- }\r
-\r
- /**\r
- * Returns total ms.\r
- * @param streamsize\r
- * @return total milliseconds\r
- */\r
- public float total_ms(int streamsize) // E.B\r
- {\r
- return(max_number_of_frames(streamsize) * ms_per_frame());\r
- }\r
-\r
- /**\r
- * Returns synchronized header.\r
- */\r
- public int getSyncHeader() // E.B\r
- {\r
- return _headerstring;\r
- }\r
-\r
- // functions which return header informations as strings:\r
- /**\r
- * Return Layer version.\r
- */\r
- public String layer_string()\r
- {\r
- switch (h_layer)\r
- {\r
- case 1:\r
- return "I";\r
- case 2:\r
- return "II";\r
- case 3:\r
- return "III";\r
- }\r
- return null;\r
- }\r
-\r
- // E.B -> private to public\r
- @LOC("T") public static final String bitrate_str[][][] = {\r
- {{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",\r
- "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s",\r
- "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s",\r
- "forbidden"},\r
- {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",\r
- "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",\r
- "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",\r
- "forbidden"},\r
- {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",\r
- "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",\r
- "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",\r
- "forbidden"}},\r
-\r
- {{"free format", "32 kbit/s", "64 kbit/s", "96 kbit/s", "128 kbit/s",\r
- "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "288 kbit/s",\r
- "320 kbit/s", "352 kbit/s", "384 kbit/s", "416 kbit/s", "448 kbit/s",\r
- "forbidden"},\r
- {"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",\r
- "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "160 kbit/s",\r
- "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s", "384 kbit/s",\r
- "forbidden"},\r
- {"free format", "32 kbit/s", "40 kbit/s", "48 kbit/s", "56 kbit/s",\r
- "64 kbit/s", "80 kbit/s" , "96 kbit/s", "112 kbit/s", "128 kbit/s",\r
- "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s",\r
- "forbidden"}},\r
- // SZD: MPEG2.5\r
- {{"free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",\r
- "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s",\r
- "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s",\r
- "forbidden"},\r
- {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",\r
- "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",\r
- "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",\r
- "forbidden"},\r
- {"free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s",\r
- "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",\r
- "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",\r
- "forbidden"}},\r
- };\r
-\r
- /**\r
- * Return Bitrate.\r
- * @return bitrate in bps\r
- */\r
- public String bitrate_string()\r
- {\r
- if (h_vbr == true)\r
- {\r
- return Integer.toString(bitrate()/1000)+" kb/s"; \r
- }\r
- else return bitrate_str[h_version][h_layer - 1][h_bitrate_index];\r
- }\r
-\r
- /**\r
- * Return Bitrate.\r
- * @return bitrate in bps and average bitrate for VBR header\r
- */\r
- public int bitrate()\r
- {\r
- if (h_vbr == true)\r
- {\r
- return ((int) ((h_vbr_bytes * 8) / (ms_per_frame() * h_vbr_frames)))*1000; \r
- }\r
- else return bitrates[h_version][h_layer - 1][h_bitrate_index];\r
- }\r
-\r
- /**\r
- * Return Instant Bitrate.\r
- * Bitrate for VBR is not constant.\r
- * @return bitrate in bps\r
- */\r
- public int bitrate_instant()\r
- {\r
- return bitrates[h_version][h_layer - 1][h_bitrate_index];\r
- }\r
-\r
- /**\r
- * Returns Frequency\r
- * @return frequency string in kHz\r
- */\r
- public String sample_frequency_string()\r
- {\r
- switch (h_sample_frequency)\r
- {\r
- case THIRTYTWO:\r
- if (h_version == MPEG1)\r
- return "32 kHz";\r
- else if (h_version == MPEG2_LSF)\r
- return "16 kHz";\r
- else // SZD\r
- return "8 kHz";\r
- case FOURTYFOUR_POINT_ONE:\r
- if (h_version == MPEG1)\r
- return "44.1 kHz";\r
- else if (h_version == MPEG2_LSF)\r
- return "22.05 kHz";\r
- else // SZD\r
- return "11.025 kHz";\r
- case FOURTYEIGHT:\r
- if (h_version == MPEG1)\r
- return "48 kHz";\r
- else if (h_version == MPEG2_LSF)\r
- return "24 kHz";\r
- else // SZD\r
- return "12 kHz";\r
- }\r
- return(null);\r
- }\r
-\r
- /**\r
- * Returns Mode.\r
- */\r
- public String mode_string()\r
- {\r
- switch (h_mode)\r
- {\r
- case STEREO:\r
- return "Stereo";\r
- case JOINT_STEREO:\r
- return "Joint stereo";\r
- case DUAL_CHANNEL:\r
- return "Dual channel";\r
- case SINGLE_CHANNEL:\r
- return "Single channel";\r
- }\r
- return null;\r
- }\r
-\r
- /**\r
- * Returns Version.\r
- * @return MPEG-1 or MPEG-2 LSF or MPEG-2.5 LSF\r
- */\r
- public String version_string()\r
- {\r
- switch (h_version)\r
- {\r
- case MPEG1:\r
- return "MPEG-1";\r
- case MPEG2_LSF:\r
- return "MPEG-2 LSF";\r
- case MPEG25_LSF: // SZD\r
- return "MPEG-2.5 LSF";\r
- }\r
- return(null);\r
- }\r
-\r
- /**\r
- * Returns the number of subbands in the current frame.\r
- * @return number of subbands\r
- */\r
- @RETURNLOC("OUT")\r
- public int number_of_subbands() {return h_number_of_subbands;}\r
-\r
- /**\r
- * Returns Intensity Stereo.\r
- * (Layer II joint stereo only).\r
- * Returns the number of subbands which are in stereo mode,\r
- * subbands above that limit are in intensity stereo mode.\r
- * @return intensity\r
- */\r
- @RETURNLOC("OUT")\r
- public int intensity_stereo_bound() {return h_intensity_stereo_bound;}\r
+public final class Header {\r
+\r
+ public static final int[][] frequencies = { { 22050, 24000, 16000, 1 },\r
+ { 44100, 48000, 32000, 1 }, { 11025, 12000, 8000, 1 } }; // SZD: MPEG25\r
+\r
+ /**\r
+ * Constant for MPEG-2 LSF version\r
+ */\r
+ public static final int MPEG2_LSF = 0;\r
+ public static final int MPEG25_LSF = 2; // SZD\r
+\r
+ /**\r
+ * Constant for MPEG-1 version\r
+ */\r
+ public static final int MPEG1 = 1;\r
+\r
+ public static final int STEREO = 0;\r
+ public static final int JOINT_STEREO = 1;\r
+ public static final int DUAL_CHANNEL = 2;\r
+ public static final int SINGLE_CHANNEL = 3;\r
+ public static final int FOURTYFOUR_POINT_ONE = 0;\r
+ public static final int FOURTYEIGHT = 1;\r
+ public static final int THIRTYTWO = 2;\r
+\r
+ @LOC("H")\r
+ private int h_layer;\r
+ @LOC("H")\r
+ private int h_protection_bit;\r
+ @LOC("H")\r
+ private int h_bitrate_index;\r
+ @LOC("H")\r
+ private int h_padding_bit;\r
+ @LOC("H")\r
+ private int h_mode_extension;\r
+ @LOC("HV")\r
+ private int h_version;\r
+ @LOC("H")\r
+ private int h_mode;\r
+ @LOC("H")\r
+ private int h_sample_frequency;\r
+ @LOC("HNS")\r
+ private int h_number_of_subbands;\r
+ @LOC("HI")\r
+ private int h_intensity_stereo_bound;\r
+ @LOC("H")\r
+ private boolean h_copyright;\r
+ @LOC("H")\r
+ private boolean h_original;\r
+ // VBR support added by E.B\r
+ @LOC("T")\r
+ private double[] h_vbr_time_per_frame = { -1.0, 384.0, 1152.0, 1152.0 };\r
+ @LOC("T")\r
+ private boolean h_vbr;\r
+ @LOC("T")\r
+ private int h_vbr_frames;\r
+ @LOC("T")\r
+ private int h_vbr_scale;\r
+ @LOC("T")\r
+ private int h_vbr_bytes;\r
+ @LOC("T")\r
+ private byte[] h_vbr_toc;\r
+\r
+ @LOC("SYNC")\r
+ private byte syncmode = Bitstream.INITIAL_SYNC;\r
+ @LOC("C")\r
+ private Crc16 crc;\r
+\r
+ @LOC("C")\r
+ public short checksum;\r
+ @LOC("FS")\r
+ public int framesize;\r
+ @LOC("NS")\r
+ public int nSlots;\r
+\r
+ @LOC("T")\r
+ private int _headerstring = -1; // E.B\r
+\r
+ Header() {\r
+ }\r
+\r
+ public String toString() {\r
+ StringBuffer buffer = new StringBuffer(200);\r
+ buffer.append("Layer ");\r
+ buffer.append(layer_string());\r
+ buffer.append(" frame ");\r
+ buffer.append(mode_string());\r
+ buffer.append(' ');\r
+ buffer.append(version_string());\r
+ if (!checksums())\r
+ buffer.append(" no");\r
+ buffer.append(" checksums");\r
+ buffer.append(' ');\r
+ buffer.append(sample_frequency_string());\r
+ buffer.append(',');\r
+ buffer.append(' ');\r
+ buffer.append(bitrate_string());\r
+\r
+ String s = buffer.toString();\r
+ return s;\r
+ }\r
+\r
+ /**\r
+ * Read a 32-bit header from the bitstream.\r
+ */\r
+ void read_header(Bitstream stream, Crc16[] crcp) throws BitstreamException {\r
+ int headerstring;\r
+ int channel_bitrate;\r
+ boolean sync = false;\r
+ do {\r
+ headerstring = stream.syncHeader(syncmode);\r
+ _headerstring = headerstring; // E.B\r
+ if (syncmode == Bitstream.INITIAL_SYNC) {\r
+ h_version = ((headerstring >>> 19) & 1);\r
+ if (((headerstring >>> 20) & 1) == 0) // SZD: MPEG2.5 detection\r
+ if (h_version == MPEG2_LSF)\r
+ h_version = MPEG25_LSF;\r
+ else\r
+ throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);\r
+ if ((h_sample_frequency = ((headerstring >>> 10) & 3)) == 3) {\r
+ throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);\r
+ }\r
+ }\r
+ h_layer = 4 - (headerstring >>> 17) & 3;\r
+ h_protection_bit = (headerstring >>> 16) & 1;\r
+ h_bitrate_index = (headerstring >>> 12) & 0xF;\r
+ h_padding_bit = (headerstring >>> 9) & 1;\r
+ h_mode = ((headerstring >>> 6) & 3);\r
+ h_mode_extension = (headerstring >>> 4) & 3;\r
+ if (h_mode == JOINT_STEREO)\r
+ h_intensity_stereo_bound = (h_mode_extension << 2) + 4;\r
+ else\r
+ h_intensity_stereo_bound = 0; // should never be used\r
+ if (((headerstring >>> 3) & 1) == 1)\r
+ h_copyright = true;\r
+ if (((headerstring >>> 2) & 1) == 1)\r
+ h_original = true;\r
+ // calculate number of subbands:\r
+ if (h_layer == 1)\r
+ h_number_of_subbands = 32;\r
+ else {\r
+ channel_bitrate = h_bitrate_index;\r
+ // calculate bitrate per channel:\r
+ if (h_mode != SINGLE_CHANNEL)\r
+ if (channel_bitrate == 4)\r
+ channel_bitrate = 1;\r
+ else\r
+ channel_bitrate -= 4;\r
+ if ((channel_bitrate == 1) || (channel_bitrate == 2))\r
+ if (h_sample_frequency == THIRTYTWO)\r
+ h_number_of_subbands = 12;\r
+ else\r
+ h_number_of_subbands = 8;\r
+ else if ((h_sample_frequency == FOURTYEIGHT)\r
+ || ((channel_bitrate >= 3) && (channel_bitrate <= 5)))\r
+ h_number_of_subbands = 27;\r
+ else\r
+ h_number_of_subbands = 30;\r
+ }\r
+ if (h_intensity_stereo_bound > h_number_of_subbands)\r
+ h_intensity_stereo_bound = h_number_of_subbands;\r
+ // calculate framesize and nSlots\r
+ calculate_framesize();\r
+ // read framedata:\r
+ int framesizeloaded = stream.read_frame_data(framesize);\r
+ if ((framesize >= 0) && (framesizeloaded != framesize)) {\r
+ // Data loaded does not match to expected framesize,\r
+ // it might be an ID3v1 TAG. (Fix 11/17/04).\r
+ throw stream.newBitstreamException(Bitstream.INVALIDFRAME);\r
+ }\r
+ if (stream.isSyncCurrentPosition(syncmode)) {\r
+ if (syncmode == Bitstream.INITIAL_SYNC) {\r
+ syncmode = Bitstream.STRICT_SYNC;\r
+ stream.set_syncword(headerstring & 0xFFF80CC0);\r
+ }\r
+ sync = true;\r
+ } else {\r
+ stream.unreadFrame();\r
+ }\r
+ } while (!sync);\r
+ stream.parse_frame();\r
+ if (h_protection_bit == 0) {\r
+ // frame contains a crc checksum\r
+ checksum = (short) stream.get_bits(16);\r
+ if (crc == null)\r
+ crc = new Crc16();\r
+ crc.add_bits(headerstring, 16);\r
+ crcp[0] = crc;\r
+ } else\r
+ crcp[0] = null;\r
+ if (h_sample_frequency == FOURTYFOUR_POINT_ONE) {\r
+ /*\r
+ * if (offset == null) { int max = max_number_of_frames(stream); offset =\r
+ * new int[max]; for(int i=0; i<max; i++) offset[i] = 0; } // E.B :\r
+ * Investigate more int cf = stream.current_frame(); int lf =\r
+ * stream.last_frame(); if ((cf > 0) && (cf == lf)) { offset[cf] =\r
+ * offset[cf-1] + h_padding_bit; } else { offset[0] = h_padding_bit; }\r
+ */\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Parse frame to extract optionnal VBR frame.\r
+ * \r
+ * @param firstframe\r
+ * @author E.B (javalayer@javazoom.net)\r
+ */\r
+ void parseVBR(byte[] firstframe) throws BitstreamException {\r
+ // Trying Xing header.\r
+ String xing = "Xing";\r
+ byte tmp[] = new byte[4];\r
+ int offset = 0;\r
+ // Compute "Xing" offset depending on MPEG version and channels.\r
+ if (h_version == MPEG1) {\r
+ if (h_mode == SINGLE_CHANNEL)\r
+ offset = 21 - 4;\r
+ else\r
+ offset = 36 - 4;\r
+ } else {\r
+ if (h_mode == SINGLE_CHANNEL)\r
+ offset = 13 - 4;\r
+ else\r
+ offset = 21 - 4;\r
+ }\r
+ try {\r
+ System.arraycopy(firstframe, offset, tmp, 0, 4);\r
+ // Is "Xing" ?\r
+ if (xing.equals(new String(tmp))) {\r
+ // Yes.\r
+ h_vbr = true;\r
+ h_vbr_frames = -1;\r
+ h_vbr_bytes = -1;\r
+ h_vbr_scale = -1;\r
+ h_vbr_toc = new byte[100];\r
+\r
+ int length = 4;\r
+ // Read flags.\r
+ byte flags[] = new byte[4];\r
+ System.arraycopy(firstframe, offset + length, flags, 0, flags.length);\r
+ length += flags.length;\r
+ // Read number of frames (if available).\r
+ if ((flags[3] & (byte) (1 << 0)) != 0) {\r
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
+ h_vbr_frames =\r
+ (tmp[0] << 24) & 0xFF000000 | (tmp[1] << 16) & 0x00FF0000 | (tmp[2] << 8)\r
+ & 0x0000FF00 | tmp[3] & 0x000000FF;\r
+ length += 4;\r
+ }\r
+ // Read size (if available).\r
+ if ((flags[3] & (byte) (1 << 1)) != 0) {\r
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
+ h_vbr_bytes =\r
+ (tmp[0] << 24) & 0xFF000000 | (tmp[1] << 16) & 0x00FF0000 | (tmp[2] << 8)\r
+ & 0x0000FF00 | tmp[3] & 0x000000FF;\r
+ length += 4;\r
+ }\r
+ // Read TOC (if available).\r
+ if ((flags[3] & (byte) (1 << 2)) != 0) {\r
+ System.arraycopy(firstframe, offset + length, h_vbr_toc, 0, h_vbr_toc.length);\r
+ length += h_vbr_toc.length;\r
+ }\r
+ // Read scale (if available).\r
+ if ((flags[3] & (byte) (1 << 3)) != 0) {\r
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
+ h_vbr_scale =\r
+ (tmp[0] << 24) & 0xFF000000 | (tmp[1] << 16) & 0x00FF0000 | (tmp[2] << 8)\r
+ & 0x0000FF00 | tmp[3] & 0x000000FF;\r
+ length += 4;\r
+ }\r
+ // System.out.println("VBR:"+xing+" Frames:"+ h_vbr_frames\r
+ // +" Size:"+h_vbr_bytes);\r
+ }\r
+ } catch (ArrayIndexOutOfBoundsException e) {\r
+ throw new BitstreamException("XingVBRHeader Corrupted", e);\r
+ }\r
+\r
+ // Trying VBRI header.\r
+ String vbri = "VBRI";\r
+ offset = 36 - 4;\r
+ try {\r
+ System.arraycopy(firstframe, offset, tmp, 0, 4);\r
+ // Is "VBRI" ?\r
+ if (vbri.equals(new String(tmp))) {\r
+ // Yes.\r
+ h_vbr = true;\r
+ h_vbr_frames = -1;\r
+ h_vbr_bytes = -1;\r
+ h_vbr_scale = -1;\r
+ h_vbr_toc = new byte[100];\r
+ // Bytes.\r
+ int length = 4 + 6;\r
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
+ h_vbr_bytes =\r
+ (tmp[0] << 24) & 0xFF000000 | (tmp[1] << 16) & 0x00FF0000 | (tmp[2] << 8) & 0x0000FF00\r
+ | tmp[3] & 0x000000FF;\r
+ length += 4;\r
+ // Frames.\r
+ System.arraycopy(firstframe, offset + length, tmp, 0, tmp.length);\r
+ h_vbr_frames =\r
+ (tmp[0] << 24) & 0xFF000000 | (tmp[1] << 16) & 0x00FF0000 | (tmp[2] << 8) & 0x0000FF00\r
+ | tmp[3] & 0x000000FF;\r
+ length += 4;\r
+ // System.out.println("VBR:"+vbri+" Frames:"+ h_vbr_frames\r
+ // +" Size:"+h_vbr_bytes);\r
+ // TOC\r
+ // TODO\r
+ }\r
+ } catch (ArrayIndexOutOfBoundsException e) {\r
+ throw new BitstreamException("VBRIVBRHeader Corrupted", e);\r
+ }\r
+ }\r
+\r
+ // Functions to query header contents:\r
+ /**\r
+ * Returns version.\r
+ */\r
+ @RETURNLOC("OUT")\r
+ public int version() {\r
+ return h_version;\r
+ }\r
+\r
+ /**\r
+ * Returns Layer ID.\r
+ */\r
+ @RETURNLOC("OUT")\r
+ public int layer() {\r
+ return h_layer;\r
+ }\r
+\r
+ /**\r
+ * Returns bitrate index.\r
+ */\r
+ @RETURNLOC("OUT")\r
+ public int bitrate_index() {\r
+ return h_bitrate_index;\r
+ }\r
+\r
+ /**\r
+ * Returns Sample Frequency.\r
+ */\r
+ public int sample_frequency() {\r
+ return h_sample_frequency;\r
+ }\r
+\r
+ /**\r
+ * Returns Frequency.\r
+ */\r
+ public int frequency() {\r
+ return frequencies[h_version][h_sample_frequency];\r
+ }\r
+\r
+ /**\r
+ * Returns Mode.\r
+ */\r
+ @RETURNLOC("OUT")\r
+ public int mode() {\r
+ return h_mode;\r
+ }\r
+\r
+ /**\r
+ * Returns Protection bit.\r
+ */\r
+ public boolean checksums() {\r
+ if (h_protection_bit == 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Returns Copyright.\r
+ */\r
+ public boolean copyright() {\r
+ return h_copyright;\r
+ }\r
+\r
+ /**\r
+ * Returns Original.\r
+ */\r
+ public boolean original() {\r
+ return h_original;\r
+ }\r
+\r
+ /**\r
+ * Return VBR.\r
+ * \r
+ * @return true if VBR header is found\r
+ */\r
+ public boolean vbr() {\r
+ return h_vbr;\r
+ }\r
+\r
+ /**\r
+ * Return VBR scale.\r
+ * \r
+ * @return scale of -1 if not available\r
+ */\r
+ public int vbr_scale() {\r
+ return h_vbr_scale;\r
+ }\r
+\r
+ /**\r
+ * Return VBR TOC.\r
+ * \r
+ * @return vbr toc ot null if not available\r
+ */\r
+ public byte[] vbr_toc() {\r
+ return h_vbr_toc;\r
+ }\r
+\r
+ /**\r
+ * Returns Checksum flag. Compares computed checksum with stream checksum.\r
+ */\r
+ @RETURNLOC("OUT")\r
+ public boolean checksum_ok() {\r
+ return (checksum == crc.checksum());\r
+ }\r
+\r
+ // Seeking and layer III stuff\r
+ /**\r
+ * Returns Layer III Padding bit.\r
+ */\r
+ public boolean padding() {\r
+ if (h_padding_bit == 0)\r
+ return false;\r
+ else\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Returns Slots.\r
+ */\r
+ @RETURNLOC("OUT")\r
+ public int slots() {\r
+ return nSlots;\r
+ }\r
+\r
+ /**\r
+ * Returns Mode Extension.\r
+ */\r
+ @RETURNLOC("OUT")\r
+ public int mode_extension() {\r
+ return h_mode_extension;\r
+ }\r
+\r
+ // E.B -> private to public\r
+ @LOC("T")\r
+ public static final int bitrates[][][] = {\r
+ {\r
+ { 0 /* free format */, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000,\r
+ 160000, 176000, 192000, 224000, 256000, 0 },\r
+ { 0 /* free format */, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000,\r
+ 96000, 112000, 128000, 144000, 160000, 0 },\r
+ { 0 /* free format */, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000,\r
+ 96000, 112000, 128000, 144000, 160000, 0 } },\r
+\r
+ {\r
+ { 0 /* free format */, 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000,\r
+ 288000, 320000, 352000, 384000, 416000, 448000, 0 },\r
+ { 0 /* free format */, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000,\r
+ 192000, 224000, 256000, 320000, 384000, 0 },\r
+ { 0 /* free format */, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000,\r
+ 160000, 192000, 224000, 256000, 320000, 0 } },\r
+ // SZD: MPEG2.5\r
+ {\r
+ { 0 /* free format */, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000,\r
+ 160000, 176000, 192000, 224000, 256000, 0 },\r
+ { 0 /* free format */, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000,\r
+ 96000, 112000, 128000, 144000, 160000, 0 },\r
+ { 0 /* free format */, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000,\r
+ 96000, 112000, 128000, 144000, 160000, 0 } },\r
+\r
+ };\r
+\r
+ // E.B -> private to public\r
+ /**\r
+ * Calculate Frame size. Calculates framesize in bytes excluding header size.\r
+ */\r
+ public int calculate_framesize() {\r
+\r
+ if (h_layer == 1) {\r
+ framesize =\r
+ (12 * bitrates[h_version][0][h_bitrate_index])\r
+ / frequencies[h_version][h_sample_frequency];\r
+ if (h_padding_bit != 0)\r
+ framesize++;\r
+ framesize <<= 2; // one slot is 4 bytes long\r
+ nSlots = 0;\r
+ } else {\r
+ framesize =\r
+ (144 * bitrates[h_version][h_layer - 1][h_bitrate_index])\r
+ / frequencies[h_version][h_sample_frequency];\r
+ if (h_version == MPEG2_LSF || h_version == MPEG25_LSF)\r
+ framesize >>= 1; // SZD\r
+ if (h_padding_bit != 0)\r
+ framesize++;\r
+ // Layer III slots\r
+ if (h_layer == 3) {\r
+ if (h_version == MPEG1) {\r
+ nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 17 : 32) // side\r
+ // info\r
+ // size\r
+ - ((h_protection_bit != 0) ? 0 : 2) // CRC size\r
+ - 4; // header size\r
+ } else { // MPEG-2 LSF, SZD: MPEG-2.5 LSF\r
+ nSlots = framesize - ((h_mode == SINGLE_CHANNEL) ? 9 : 17) // side\r
+ // info\r
+ // size\r
+ - ((h_protection_bit != 0) ? 0 : 2) // CRC size\r
+ - 4; // header size\r
+ }\r
+ } else {\r
+ nSlots = 0;\r
+ }\r
+ }\r
+ framesize -= 4; // subtract header size\r
+ return framesize;\r
+ }\r
+\r
+ /**\r
+ * Returns the maximum number of frames in the stream.\r
+ * \r
+ * @param streamsize\r
+ * @return number of frames\r
+ */\r
+ public int max_number_of_frames(int streamsize) // E.B\r
+ {\r
+ if (h_vbr == true)\r
+ return h_vbr_frames;\r
+ else {\r
+ if ((framesize + 4 - h_padding_bit) == 0)\r
+ return 0;\r
+ else\r
+ return (streamsize / (framesize + 4 - h_padding_bit));\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the maximum number of frames in the stream.\r
+ * \r
+ * @param streamsize\r
+ * @return number of frames\r
+ */\r
+ public int min_number_of_frames(int streamsize) // E.B\r
+ {\r
+ if (h_vbr == true)\r
+ return h_vbr_frames;\r
+ else {\r
+ if ((framesize + 5 - h_padding_bit) == 0)\r
+ return 0;\r
+ else\r
+ return (streamsize / (framesize + 5 - h_padding_bit));\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns ms/frame.\r
+ * \r
+ * @return milliseconds per frame\r
+ */\r
+ public float ms_per_frame() // E.B\r
+ {\r
+ if (h_vbr == true) {\r
+ double tpf = h_vbr_time_per_frame[layer()] / frequency();\r
+ if ((h_version == MPEG2_LSF) || (h_version == MPEG25_LSF))\r
+ tpf /= 2;\r
+ return ((float) (tpf * 1000));\r
+ } else {\r
+ float ms_per_frame_array[][] =\r
+ { { 8.707483f, 8.0f, 12.0f }, { 26.12245f, 24.0f, 36.0f }, { 26.12245f, 24.0f, 36.0f } };\r
+ return (ms_per_frame_array[h_layer - 1][h_sample_frequency]);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns total ms.\r
+ * \r
+ * @param streamsize\r
+ * @return total milliseconds\r
+ */\r
+ public float total_ms(int streamsize) // E.B\r
+ {\r
+ return (max_number_of_frames(streamsize) * ms_per_frame());\r
+ }\r
+\r
+ /**\r
+ * Returns synchronized header.\r
+ */\r
+ public int getSyncHeader() // E.B\r
+ {\r
+ return _headerstring;\r
+ }\r
+\r
+ // functions which return header informations as strings:\r
+ /**\r
+ * Return Layer version.\r
+ */\r
+ public String layer_string() {\r
+ switch (h_layer) {\r
+ case 1:\r
+ return "I";\r
+ case 2:\r
+ return "II";\r
+ case 3:\r
+ return "III";\r
+ }\r
+ return null;\r
+ }\r
+\r
+ // E.B -> private to public\r
+ @LOC("T")\r
+ public static final String bitrate_str[][][] = {\r
+ {\r
+ { "free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",\r
+ "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s", "176 kbit/s",\r
+ "192 kbit/s", "224 kbit/s", "256 kbit/s", "forbidden" },\r
+ { "free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", "40 kbit/s",\r
+ "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", "96 kbit/s", "112 kbit/s",\r
+ "128 kbit/s", "144 kbit/s", "160 kbit/s", "forbidden" },\r
+ { "free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", "40 kbit/s",\r
+ "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", "96 kbit/s", "112 kbit/s",\r
+ "128 kbit/s", "144 kbit/s", "160 kbit/s", "forbidden" } },\r
+\r
+ {\r
+ { "free format", "32 kbit/s", "64 kbit/s", "96 kbit/s", "128 kbit/s", "160 kbit/s",\r
+ "192 kbit/s", "224 kbit/s", "256 kbit/s", "288 kbit/s", "320 kbit/s", "352 kbit/s",\r
+ "384 kbit/s", "416 kbit/s", "448 kbit/s", "forbidden" },\r
+ { "free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",\r
+ "96 kbit/s", "112 kbit/s", "128 kbit/s", "160 kbit/s", "192 kbit/s", "224 kbit/s",\r
+ "256 kbit/s", "320 kbit/s", "384 kbit/s", "forbidden" },\r
+ { "free format", "32 kbit/s", "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s",\r
+ "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "160 kbit/s", "192 kbit/s",\r
+ "224 kbit/s", "256 kbit/s", "320 kbit/s", "forbidden" } },\r
+ // SZD: MPEG2.5\r
+ {\r
+ { "free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",\r
+ "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s", "176 kbit/s",\r
+ "192 kbit/s", "224 kbit/s", "256 kbit/s", "forbidden" },\r
+ { "free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", "40 kbit/s",\r
+ "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", "96 kbit/s", "112 kbit/s",\r
+ "128 kbit/s", "144 kbit/s", "160 kbit/s", "forbidden" },\r
+ { "free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", "40 kbit/s",\r
+ "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", "96 kbit/s", "112 kbit/s",\r
+ "128 kbit/s", "144 kbit/s", "160 kbit/s", "forbidden" } }, };\r
+\r
+ /**\r
+ * Return Bitrate.\r
+ * \r
+ * @return bitrate in bps\r
+ */\r
+ public String bitrate_string() {\r
+ if (h_vbr == true) {\r
+ return Integer.toString(bitrate() / 1000) + " kb/s";\r
+ } else\r
+ return bitrate_str[h_version][h_layer - 1][h_bitrate_index];\r
+ }\r
+\r
+ /**\r
+ * Return Bitrate.\r
+ * \r
+ * @return bitrate in bps and average bitrate for VBR header\r
+ */\r
+ public int bitrate() {\r
+ if (h_vbr == true) {\r
+ return ((int) ((h_vbr_bytes * 8) / (ms_per_frame() * h_vbr_frames))) * 1000;\r
+ } else\r
+ return bitrates[h_version][h_layer - 1][h_bitrate_index];\r
+ }\r
+\r
+ /**\r
+ * Return Instant Bitrate. Bitrate for VBR is not constant.\r
+ * \r
+ * @return bitrate in bps\r
+ */\r
+ public int bitrate_instant() {\r
+ return bitrates[h_version][h_layer - 1][h_bitrate_index];\r
+ }\r
+\r
+ /**\r
+ * Returns Frequency\r
+ * \r
+ * @return frequency string in kHz\r
+ */\r
+ public String sample_frequency_string() {\r
+ switch (h_sample_frequency) {\r
+ case THIRTYTWO:\r
+ if (h_version == MPEG1)\r
+ return "32 kHz";\r
+ else if (h_version == MPEG2_LSF)\r
+ return "16 kHz";\r
+ else\r
+ // SZD\r
+ return "8 kHz";\r
+ case FOURTYFOUR_POINT_ONE:\r
+ if (h_version == MPEG1)\r
+ return "44.1 kHz";\r
+ else if (h_version == MPEG2_LSF)\r
+ return "22.05 kHz";\r
+ else\r
+ // SZD\r
+ return "11.025 kHz";\r
+ case FOURTYEIGHT:\r
+ if (h_version == MPEG1)\r
+ return "48 kHz";\r
+ else if (h_version == MPEG2_LSF)\r
+ return "24 kHz";\r
+ else\r
+ // SZD\r
+ return "12 kHz";\r
+ }\r
+ return (null);\r
+ }\r
+\r
+ /**\r
+ * Returns Mode.\r
+ */\r
+ public String mode_string() {\r
+ switch (h_mode) {\r
+ case STEREO:\r
+ return "Stereo";\r
+ case JOINT_STEREO:\r
+ return "Joint stereo";\r
+ case DUAL_CHANNEL:\r
+ return "Dual channel";\r
+ case SINGLE_CHANNEL:\r
+ return "Single channel";\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Returns Version.\r
+ * \r
+ * @return MPEG-1 or MPEG-2 LSF or MPEG-2.5 LSF\r
+ */\r
+ public String version_string() {\r
+ switch (h_version) {\r
+ case MPEG1:\r
+ return "MPEG-1";\r
+ case MPEG2_LSF:\r
+ return "MPEG-2 LSF";\r
+ case MPEG25_LSF: // SZD\r
+ return "MPEG-2.5 LSF";\r
+ }\r
+ return (null);\r
+ }\r
+\r
+ /**\r
+ * Returns the number of subbands in the current frame.\r
+ * \r
+ * @return number of subbands\r
+ */\r
+ @RETURNLOC("OUT")\r
+ public int number_of_subbands() {\r
+ return h_number_of_subbands;\r
+ }\r
+\r
+ /**\r
+ * Returns Intensity Stereo. (Layer II joint stereo only). Returns the number\r
+ * of subbands which are in stereo mode, subbands above that limit are in\r
+ * intensity stereo mode.\r
+ * \r
+ * @return intensity\r
+ */\r
+ @RETURNLOC("OUT")\r
+ public int intensity_stereo_bound() {\r
+ return h_intensity_stereo_bound;\r
+ }\r
}\r