[xiph-commits] r17092 - in trunk: . rhea rhea/com rhea/com/jcraft rhea/com/jcraft/player rhea/com/meviatronic rhea/com/meviatronic/zeus rhea/com/meviatronic/zeus/castor rhea/com/meviatronic/zeus/helen rhea/com/meviatronic/zeus/pollux rhea/org rhea/org/xiph rhea/org/xiph/ogg

mike at svn.xiph.org mike at svn.xiph.org
Sat Mar 27 09:16:05 PDT 2010


Author: mike
Date: 2010-03-27 09:16:05 -0700 (Sat, 27 Mar 2010)
New Revision: 17092

Added:
   trunk/rhea/
   trunk/rhea/README.txt
   trunk/rhea/com/
   trunk/rhea/com/jcraft/
   trunk/rhea/com/jcraft/player/
   trunk/rhea/com/jcraft/player/AudioPlayer.java
   trunk/rhea/com/meviatronic/
   trunk/rhea/com/meviatronic/zeus/
   trunk/rhea/com/meviatronic/zeus/castor/
   trunk/rhea/com/meviatronic/zeus/castor/AudioReader.java
   trunk/rhea/com/meviatronic/zeus/castor/EndOfMediaException.java
   trunk/rhea/com/meviatronic/zeus/castor/EndOfPacketException.java
   trunk/rhea/com/meviatronic/zeus/castor/Imdct.java
   trunk/rhea/com/meviatronic/zeus/castor/Output.java
   trunk/rhea/com/meviatronic/zeus/castor/README.txt
   trunk/rhea/com/meviatronic/zeus/castor/VorbisDecoder.java
   trunk/rhea/com/meviatronic/zeus/helen/
   trunk/rhea/com/meviatronic/zeus/helen/BaseTag.java
   trunk/rhea/com/meviatronic/zeus/helen/Converter.java
   trunk/rhea/com/meviatronic/zeus/helen/OggTag.java
   trunk/rhea/com/meviatronic/zeus/helen/README.txt
   trunk/rhea/com/meviatronic/zeus/helen/Tag.java
   trunk/rhea/com/meviatronic/zeus/helen/TagException.java
   trunk/rhea/com/meviatronic/zeus/pollux/
   trunk/rhea/com/meviatronic/zeus/pollux/MemoryImageSource.java
   trunk/rhea/com/meviatronic/zeus/pollux/Output.java
   trunk/rhea/com/meviatronic/zeus/pollux/README.txt
   trunk/rhea/com/meviatronic/zeus/pollux/TheoraDecoder.java
   trunk/rhea/com/meviatronic/zeus/pollux/VideoReader.java
   trunk/rhea/org/
   trunk/rhea/org/xiph/
   trunk/rhea/org/xiph/ogg/
   trunk/rhea/org/xiph/ogg/Packet.java
   trunk/rhea/org/xiph/ogg/Page.java
   trunk/rhea/org/xiph/ogg/StreamState.java
   trunk/rhea/org/xiph/ogg/SyncState.java
Log:
Initial import ...

Added: trunk/rhea/README.txt
===================================================================
--- trunk/rhea/README.txt	                        (rev 0)
+++ trunk/rhea/README.txt	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,19 @@
+	Rhea, a fast Theora/Vorbis player created by Michael Scheerer.
+	Rhea player (c) 2009 Michael Scheerer www.meviatronic.com
+
+	Many thanks to
+	Monty <monty at xiph.org> and
+	The XIPHOPHORUS Company http://www.xiph.org/ .
+	
+	Rhea is intendend to be a pure Theora/Vorbis player without an underlying
+	multimedia framework. Rhea can be integrated into a Java Sound API plugin,
+	like the Vorbis plugin deployed from www.javazoom.net
+	
+	Currently only the audio part together with an audio player is ready.
+	But it's still usable as a Java Sound API plugin for other open source projects like
+	the one here: http://www.javazoom.net/vorbisspi/vorbisspi.html
+	 
+	See:
+ 	https://svn.xiph.org/trunk/rhea/com/meviatronic/zeus/helen.README.txt
+ 	https://svn.xiph.org/trunk/rhea/com/meviatronic/zeus/castor.README.txt
+ 	https://svn.xiph.org/trunk/rhea/com/meviatronic/zeus/pollux.README.txt

Added: trunk/rhea/com/jcraft/player/AudioPlayer.java
===================================================================
--- trunk/rhea/com/jcraft/player/AudioPlayer.java	                        (rev 0)
+++ trunk/rhea/com/jcraft/player/AudioPlayer.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,1113 @@
+/* Audio player, created by JCraft.
+ *
+ * Audio player (c) 2000 ymnk, JCraft,Inc. <ymnk at jcraft.com>
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.jcraft.player;
+
+import com.meviatronic.zeus.castor.*;
+import com.meviatronic.zeus.helena.*;
+import org.xiph.ogg.*;
+
+import java.util.*;
+import java.net.*;
+import java.io.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.applet.*;
+import javax.swing.*;
+import javax.sound.sampled.*;
+
+/**
+ * @author Xiph, Michael Scheerer (Adaptions, Fixes)
+ */
+public class AudioPlayer extends JApplet implements ActionListener, Runnable{
+
+  private static final long serialVersionUID=1L;
+
+  boolean running_as_applet=true;
+
+  Thread player=null;
+  InputStream bitStream=null;
+
+  int udp_port=-1;
+  String udp_baddress=null;
+
+  static AppletContext acontext=null;
+
+  static final int BUFSIZE=4096*2;
+  
+  static byte[] convbuffer;
+
+  private int RETRY=3;
+  int retry=RETRY;
+
+  String playlistfile="playlist";
+
+  boolean icestats=false;
+
+  SyncState oy;
+  StreamState os;
+  Page og;
+  Packet op;
+  AudioReader vi;
+  Output vo;
+
+  byte[] buffer=null;
+  int bytes=0;
+
+  int format;
+  int sampleRate=0;
+  int channels=0;
+  int left_vol_scale=100;
+  int right_vol_scale=100;
+  SourceDataLine outputLine=null;
+  String current_source=null;
+
+  int frameSizeInBytes;
+  int bufferLengthInBytes;
+
+  boolean playonstartup=false;
+
+  public void init(){
+    running_as_applet=true;
+
+    acontext=getAppletContext();
+
+    String s=getParameter("jorbis.player.playlist");
+    playlistfile=s;
+
+    s=getParameter("jorbis.player.icestats");
+    if(s!=null&&s.equals("yes")){
+      icestats=true;
+    }
+
+    loadPlaylist();
+    initUI();
+
+    if(playlist.size()>0){
+      s=getParameter("jorbis.player.playonstartup");
+      if(s!=null&&s.equals("yes")){
+        playonstartup=true;
+      }
+    }
+
+    setBackground(Color.lightGray);
+    //  setBackground(Color.white);
+    getContentPane().setLayout(new BorderLayout());
+    getContentPane().add(panel);
+  }
+
+  public void start(){
+    super.start();
+    if(playonstartup){
+      play_sound();
+    }
+  }
+
+	void init_jorbis(){
+    oy=new SyncState();
+    os=new StreamState();
+    og=new Page();
+    op=new Packet();
+	vi=new AudioReader();
+    
+    buffer=null;
+    bytes=0;
+	oy.init();
+  }
+
+  SourceDataLine getOutputLine(int channels, int sampleRate){
+    if(outputLine==null||this.sampleRate!=sampleRate||this.channels!=channels){
+      if(outputLine!=null){
+        outputLine.drain();
+        outputLine.stop();
+        outputLine.close();
+      }
+      init_audio(channels, sampleRate);
+      outputLine.start();
+    }
+    return outputLine;
+  }
+
+  void init_audio(int channels, int sampleRate){
+    try{
+      //ClassLoader originalClassLoader=null;
+      //try{
+      //  originalClassLoader=Thread.currentThread().getContextClassLoader();
+      //  Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
+      //}
+      //catch(Exception ee){
+      //  System.out.println(ee);
+      //}
+      AudioFormat audioFormat=new AudioFormat((float)sampleRate, 16, channels, true, // PCM_Signed
+          false // littleEndian
+      );
+      DataLine.Info info=new DataLine.Info(SourceDataLine.class, audioFormat, AudioSystem.NOT_SPECIFIED);
+      if(!AudioSystem.isLineSupported(info)){
+        //System.out.println("Line " + info + " not supported.");
+        return;
+      }
+
+      try{
+        outputLine=(SourceDataLine)AudioSystem.getLine(info);
+        //outputLine.addLineListener(this);
+        outputLine.open(audioFormat);
+      }
+      catch(LineUnavailableException ex){
+        System.out.println("Unable to open the sourceDataLine: "+ex);
+        return;
+      }
+      catch(IllegalArgumentException ex){
+        System.out.println("Illegal Argument: "+ex);
+        return;
+      }
+
+      frameSizeInBytes=audioFormat.getFrameSize();
+      int bufferLengthInFrames=outputLine.getBufferSize()/frameSizeInBytes/2;
+      bufferLengthInBytes=bufferLengthInFrames*frameSizeInBytes;
+
+      //if(originalClassLoader!=null)
+      //  Thread.currentThread().setContextClassLoader(originalClassLoader);
+
+      this.sampleRate=sampleRate;
+      this.channels=channels;
+    }
+    catch(Exception ee){
+      System.out.println(ee);
+    }
+  }
+
+  private int item2index(String item){
+    for(int i=0; i<cb.getItemCount(); i++){
+      String foo=(String)(cb.getItemAt(i));
+      if(item.equals(foo))
+        return i;
+    }
+    cb.addItem(item);
+    return cb.getItemCount()-1;
+  }
+
+	public synchronized void run(){
+    Thread me=Thread.currentThread();
+    String item=(String)(cb.getSelectedItem());
+    int current_index=item2index(item);
+	 while(true){
+      item=(String)(cb.getItemAt(current_index));
+		cb.setSelectedIndex(current_index);
+      bitStream=selectSource(item);
+      if(bitStream!=null){
+        if(udp_port!=-1){
+          play_udp_stream(me);
+        }
+		  else{
+			  play_stream(me,item);
+        }
+      }
+      else if(cb.getItemCount()==1){
+        break;
+      }
+      if(player!=me){
+        break;
+      }
+      
+      current_index++;
+      if(current_index>=cb.getItemCount()){
+        current_index=0;
+      }
+      if(cb.getItemCount()<=0)
+			break;
+    }
+     
+	  start_button.setText("start");
+	  stop();
+  }
+
+  private void play_stream(Thread me,String item){
+
+    boolean chained=false;
+
+    init_jorbis();
+
+    retry=RETRY;
+
+    //System.out.println("play_stream>");
+
+    loop: while(true){
+      int eos=0;
+
+      int index=oy.buffer(BUFSIZE);
+      buffer=oy.data;
+      try{
+        bytes=bitStream.read(buffer, index, BUFSIZE);
+      }
+      catch(Exception e){
+        System.err.println(e+" "+buffer+" "+bitStream);
+        return;
+      }
+      oy.wrote(bytes);
+
+      if(chained){ //
+        chained=false; //
+      } //
+      else{ //
+        if(oy.pageout(og)!=1){
+          if(bytes<BUFSIZE)
+            break;
+          System.err.println("Input does not appear to be an Ogg bitstream.");
+          return;
+        }
+      } //
+      os.init(og.serialno());
+      os.reset();
+
+      if(os.pagein(og)<0){
+        // error; stream version mismatch perhaps
+        System.err.println("Error reading first page of Ogg bitstream data.");
+        return;
+      }
+
+      retry=RETRY;
+
+      if(os.packetout(op)!=1){
+        // no page? must not be vorbis
+        System.out.println("Error reading initial header packet.");
+        break;
+        //      return;
+      }
+		
+		try {
+			vi.readMediaInformation(op);
+		} catch (Exception e) {
+			System.out.println("This Ogg bitstream does not contain Vorbis audio data.");
+			stop();
+			return;
+		}
+      
+
+      int i=0;
+
+      while(i<2){
+        while(i<2){
+          int result=oy.pageout(og);
+          if(result==0)
+            break; // Need more data
+          if(result==1){
+            os.pagein(og);
+            while(i<2){
+              result=os.packetout(op);
+              if(result==0)
+                break;
+              if(result==-1){
+                System.out.println("Corrupt secondary header.  Exiting.");
+                //return;
+                break loop;
+			  }
+				try {
+					vi.readMediaInformation(op);
+				} catch (Exception e) {
+					stop();
+				}
+              i++;
+            }
+          }
+        }
+
+        index=oy.buffer(BUFSIZE);
+        buffer=oy.data;
+        try{
+          bytes=bitStream.read(buffer, index, BUFSIZE);
+        }
+        catch(Exception e){
+          System.err.println(e);
+          return;
+        }
+        if(bytes==0&&i<2){
+          System.err.println("End of file before finding all Vorbis headers!");
+          return;
+        }
+        oy.wrote(bytes);
+      }
+		
+		
+		System.out.println(vi.getOggCommentContent());
+		if (acontext != null) {
+			acontext.showStatus(vi.getOggCommentContent());
+		}
+		   
+		if (vo == null) {
+			vo = new VorbisDecoder(vi);
+		}
+     
+      float[][][] pcmf = new float [1][][];
+      int[] _index=new int[vi.channels];
+
+      getOutputLine(vi.channels, vi.sampleRate);
+
+      while(eos==0){
+        while(eos==0){
+
+			if(player!=me){
+				stop();
+            	return;
+          }
+
+          int result=oy.pageout(og);
+          if(result==0)
+            break; // need more data
+          if(result==-1){ // missing or corrupt data at this page position
+          //	    System.err.println("Corrupt or missing data in bitstream; continuing...");
+          }
+          else{
+            os.pagein(og);
+
+            if(og.granulepos()==0){ //
+              chained=true; //
+              eos=1; //
+              break; //
+            } //
+
+            while(true){
+              result=os.packetout(op);
+              if(result==0)
+                break; // need more data
+              if(result==-1){ // missing or corrupt data at this page position
+                // no reason to complain; already complained above
+
+                //System.err.println("no reason to complain; already complained above");
+              }
+              else{
+                // we have a packet.  Decode it
+				  
+				  try {
+					convbuffer = vo.synthesis(op);
+				  } catch (Exception e) {
+					  
+				  }
+				  outputLine.write(convbuffer, 2 * vo.getSampleOffset(), 2 * vo.getNumberOfSamples());
+              }
+            }
+            if(og.eos()!=0)
+              eos=1;
+          }
+        }
+
+		  if(eos==0){
+          index=oy.buffer(BUFSIZE);
+          buffer=oy.data;
+          try{
+            bytes=bitStream.read(buffer, index, BUFSIZE);
+          }
+          catch(Exception e){
+            System.err.println(e);
+            return;
+          }
+          if(bytes==-1){
+            break;
+          }
+          oy.wrote(bytes);
+          if(bytes==0)
+            eos=1;
+        }
+      }
+    }
+	stop();
+  }
+
+  private void play_udp_stream(Thread me){
+    init_jorbis();
+
+    try{
+      loop: while(true){
+        int index=oy.buffer(BUFSIZE);
+        buffer=oy.data;
+        try{
+          bytes=bitStream.read(buffer, index, BUFSIZE);
+        }
+        catch(Exception e){
+          System.err.println(e);
+          return;
+        }
+
+        oy.wrote(bytes);
+        if(oy.pageout(og)!=1){
+          //        if(bytes<BUFSIZE)break;
+          System.err.println("Input does not appear to be an Ogg bitstream.");
+          return;
+        }
+
+        os.init(og.serialno());
+        os.reset();
+
+        if(os.pagein(og)<0){
+          // error; stream version mismatch perhaps
+          System.err.println("Error reading first page of Ogg bitstream data.");
+          return;
+        }
+
+        if(os.packetout(op)!=1){
+          // no page? must not be vorbis
+          System.err.println("Error reading initial header packet.");
+          //        break;
+          return;
+        }
+		  
+		  try {
+			  vi.readMediaInformation(op);
+		  } catch (Exception e) {
+			  stop();
+		  }
+        
+
+        int i=0;
+        while(i<2){
+          while(i<2){
+            int result=oy.pageout(og);
+            if(result==0)
+              break; // Need more data
+            if(result==1){
+              os.pagein(og);
+              while(i<2){
+                result=os.packetout(op);
+                if(result==0)
+                  break;
+                if(result==-1){
+                  System.err.println("Corrupt secondary header.  Exiting.");
+                  //return;
+                  break loop;
+				}
+				  
+				  try {
+					  vi.readMediaInformation(op);
+				  } catch (Exception e) {
+					  stop();
+				  }
+                i++;
+              }
+            }
+          }
+
+          if(i==2)
+            break;
+
+          index=oy.buffer(BUFSIZE);
+          buffer=oy.data;
+          try{
+            bytes=bitStream.read(buffer, index, BUFSIZE);
+          }
+			catch(Exception e){
+				stop();
+            System.err.println(e);
+            return;
+          }
+			if(bytes==0&&i<2){
+				stop();
+            System.err
+                .println("End of file before finding all Vorbis headers!");
+            return;
+          }
+          oy.wrote(bytes);
+        }
+        break;
+      }
+    }
+    catch(Exception e){
+    }
+	  
+    stop();
+
+    UDPIO io=null;
+    io=new UDPIO(udp_port);
+    
+
+    bitStream=io;
+    play_stream(me,null);
+  }
+
+	public synchronized void stop(){
+    	if (os != null) {
+			os.close();
+		}
+		if (vo != null) {
+			vo.close();
+		}
+		if (vi != null) {
+			vi.close();
+		}
+		if (oy != null) {
+			oy.close();
+		}
+		if (og != null) {
+			og.close();
+		}
+		if (outputLine != null) {
+			outputLine.drain();
+        	outputLine.stop();
+        	outputLine.close();
+			outputLine = null;
+		}
+		try {
+			if(bitStream != null) {
+				bitStream.close();
+			}
+			bitStream = null;
+		} catch (Exception e) {
+			
+		}
+		
+		os = null;
+      	vo = null;
+      	vi = null;
+		oy = null;
+		og = null;
+		buffer = null;
+  	}
+
+  Vector playlist=new Vector();
+
+  public void actionPerformed(ActionEvent e){
+
+    if(e.getSource()==stats_button){
+      String item=(String)(cb.getSelectedItem());
+      if(!item.startsWith("http://"))
+        return;
+      if(item.endsWith(".pls")){
+        item=fetch_pls(item);
+        if(item==null)
+          return;
+      }
+      else if(item.endsWith(".m3u")){
+        item=fetch_m3u(item);
+        if(item==null)
+          return;
+      }
+      byte[] foo=item.getBytes();
+      for(int i=foo.length-1; i>=0; i--){
+        if(foo[i]=='/'){
+          item=item.substring(0, i+1)+"stats.xml";
+          break;
+        }
+      }
+      System.out.println(item);
+      try{
+        URL url=null;
+        if(running_as_applet)
+          url=new URL(getCodeBase(), item);
+        else
+          url=new URL(item);
+        BufferedReader stats=new BufferedReader(new InputStreamReader(url
+            .openConnection().getInputStream()));
+        while(true){
+          String bar=stats.readLine();
+          if(bar==null)
+            break;
+          System.out.println(bar);
+        }
+      }
+      catch(Exception ee){
+        System.err.println(ee);
+      }
+      return;
+    }
+
+    String command=((JButton)(e.getSource())).getText();
+    if(command.equals("start")&&player==null){
+      play_sound();
+    }
+    else if(player!=null){
+      stop_sound();
+    }
+  }
+
+  public String getTitle(){
+    return (String)(cb.getSelectedItem());
+  }
+
+  public void play_sound(){
+    if(player!=null)
+      return;
+    player=new Thread(this);
+    start_button.setText("stop");
+    player.start();
+  }
+
+	public void stop_sound(){
+    if(player==null)
+      return;
+	  player=null;
+		start_button.setText("start");
+  }
+
+  InputStream selectSource(String item){
+    if(item.endsWith(".pls")){
+      item=fetch_pls(item);
+      if(item==null)
+        return null;
+      //System.out.println("fetch: "+item);
+    }
+    else if(item.endsWith(".m3u")){
+      item=fetch_m3u(item);
+      if(item==null)
+        return null;
+      //System.out.println("fetch: "+item);
+    }
+
+    if(!item.endsWith(".ogg")){
+      return null;
+    }
+
+    InputStream is=null;
+    URLConnection urlc=null;
+    try{
+      URL url=null;
+      if(running_as_applet)
+        url=new URL(getCodeBase(), item);
+      else
+        url=new URL(item);
+      urlc=url.openConnection();
+      is=urlc.getInputStream();
+      current_source=url.getProtocol()+"://"+url.getHost()+":"+url.getPort()
+          +url.getFile();
+    }
+    catch(Exception ee){
+      //System.err.println(ee);
+    }
+
+    if(is==null&&!running_as_applet){
+      try{
+        is=new FileInputStream(System.getProperty("user.dir")
+            +System.getProperty("file.separator")+item);
+        current_source=null;
+      }
+      catch(Exception ee){
+        //System.err.println(ee);
+      }
+    }
+
+    if(is==null)
+      return null;
+
+    //System.out.println("Select: "+item);
+
+    {
+      boolean find=false;
+      for(int i=0; i<cb.getItemCount(); i++){
+        String foo=(String)(cb.getItemAt(i));
+        if(item.equals(foo)){
+          find=true;
+          break;
+        }
+      }
+      if(!find){
+        cb.addItem(item);
+      }
+    }
+
+    int i=0;
+    String s=null;
+    String t=null;
+    udp_port=-1;
+    udp_baddress=null;
+    while(urlc!=null&&true){
+      s=urlc.getHeaderField(i);
+      t=urlc.getHeaderFieldKey(i);
+      if(s==null)
+        break;
+      i++;
+      if(t!=null&&t.equals("udp-port")){
+        try{
+          udp_port=Integer.parseInt(s);
+        }
+        catch(Exception ee){
+          System.err.println(ee);
+        }
+      }
+      else if(t!=null&&t.equals("udp-broadcast-address")){
+        udp_baddress=s;
+      }
+    }
+    return is;
+  }
+
+  String fetch_pls(String pls){
+    InputStream pstream=null;
+    if(pls.startsWith("http://")){
+      try{
+        URL url=null;
+        if(running_as_applet)
+          url=new URL(getCodeBase(), pls);
+        else
+          url=new URL(pls);
+        URLConnection urlc=url.openConnection();
+        pstream=urlc.getInputStream();
+      }
+      catch(Exception ee){
+        System.err.println(ee);
+        return null;
+      }
+    }
+    if(pstream==null&&!running_as_applet){
+      try{
+        pstream=new FileInputStream(System.getProperty("user.dir")
+            +System.getProperty("file.separator")+pls);
+      }
+      catch(Exception ee){
+        System.err.println(ee);
+        return null;
+      }
+    }
+
+    String line=null;
+    while(true){
+      try{
+        line=readline(pstream);
+      }
+      catch(Exception e){
+      }
+      if(line==null)
+        break;
+      if(line.startsWith("File1=")){
+        byte[] foo=line.getBytes();
+        int i=6;
+        for(; i<foo.length; i++){
+          if(foo[i]==0x0d)
+            break;
+        }
+        return line.substring(6, i);
+      }
+    }
+    return null;
+  }
+
+  String fetch_m3u(String m3u){
+    InputStream pstream=null;
+    if(m3u.startsWith("http://")){
+      try{
+        URL url=null;
+        if(running_as_applet)
+          url=new URL(getCodeBase(), m3u);
+        else
+          url=new URL(m3u);
+        URLConnection urlc=url.openConnection();
+        pstream=urlc.getInputStream();
+      }
+      catch(Exception ee){
+        System.err.println(ee);
+        return null;
+      }
+    }
+    if(pstream==null&&!running_as_applet){
+      try{
+        pstream=new FileInputStream(System.getProperty("user.dir")
+            +System.getProperty("file.separator")+m3u);
+      }
+      catch(Exception ee){
+        System.err.println(ee);
+        return null;
+      }
+    }
+
+    String line=null;
+    while(true){
+      try{
+        line=readline(pstream);
+      }
+      catch(Exception e){
+      }
+      if(line==null)
+        break;
+      return line;
+    }
+    return null;
+  }
+
+  void loadPlaylist(){
+
+    if(running_as_applet){
+      String s=null;
+      for(int i=0; i<10; i++){
+        s=getParameter("jorbis.player.play."+i);
+        if(s==null)
+          break;
+        playlist.addElement(s);
+      }
+    }
+
+    if(playlistfile==null){
+      return;
+    }
+
+    try{
+      InputStream is=null;
+      try{
+        URL url=null;
+        if(running_as_applet)
+          url=new URL(getCodeBase(), playlistfile);
+        else
+          url=new URL(playlistfile);
+        URLConnection urlc=url.openConnection();
+        is=urlc.getInputStream();
+      }
+      catch(Exception ee){
+      }
+      if(is==null&&!running_as_applet){
+        try{
+          is=new FileInputStream(System.getProperty("user.dir")
+              +System.getProperty("file.separator")+playlistfile);
+        }
+        catch(Exception ee){
+        }
+      }
+
+      if(is==null)
+        return;
+
+      while(true){
+        String line=readline(is);
+        if(line==null)
+          break;
+        byte[] foo=line.getBytes();
+        for(int i=0; i<foo.length; i++){
+          if(foo[i]==0x0d){
+            line=new String(foo, 0, i);
+            break;
+          }
+        }
+        playlist.addElement(line);
+      }
+    }
+    catch(Exception e){
+      System.out.println(e);
+    }
+  }
+
+  private String readline(InputStream is){
+    StringBuffer rtn=new StringBuffer();
+    int temp;
+    do{
+      try{
+        temp=is.read();
+      }
+      catch(Exception e){
+        return (null);
+      }
+      if(temp==-1){
+        String str=rtn.toString();
+        if(str.length()==0)
+          return (null);
+        return str;
+      }
+      if(temp!=0&&temp!='\n'&&temp!='\r')
+        rtn.append((char)temp);
+    }
+    while(temp!='\n'&&temp!='\r');
+    return (rtn.toString());
+  }
+
+  JPanel panel;
+  JComboBox cb;
+  JButton start_button;
+  JButton stats_button;
+
+  void initUI(){
+    panel=new JPanel();
+
+    cb=new JComboBox(playlist);
+    cb.setEditable(true);
+    panel.add(cb);
+
+    start_button=new JButton("start");
+    start_button.addActionListener(this);
+    panel.add(start_button);
+
+    if(icestats){
+      stats_button=new JButton("IceStats");
+      stats_button.addActionListener(this);
+      panel.add(stats_button);
+    }
+  }
+
+  class UDPIO extends InputStream {
+    InetAddress address;
+    DatagramSocket socket=null;
+    DatagramPacket sndpacket;
+    DatagramPacket recpacket;
+    byte[] buf=new byte[1024];
+    //String host;
+    int port;
+    byte[] inbuffer=new byte[2048];
+    byte[] outbuffer=new byte[1024];
+    int instart=0, inend=0, outindex=0;
+
+    UDPIO(int port){
+      this.port=port;
+      try{
+        socket=new DatagramSocket(port);
+      }
+      catch(Exception e){
+        System.err.println(e);
+      }
+      recpacket=new DatagramPacket(buf, 1024);
+    }
+
+    void setTimeout(int i){
+      try{
+        socket.setSoTimeout(i);
+      }
+      catch(Exception e){
+        System.out.println(e);
+      }
+    }
+
+    int getByte() throws java.io.IOException{
+      if((inend-instart)<1){
+        read(1);
+      }
+      return inbuffer[instart++]&0xff;
+    }
+
+    int getByte(byte[] array) throws java.io.IOException{
+      return getByte(array, 0, array.length);
+    }
+
+    int getByte(byte[] array, int begin, int length) throws java.io.IOException{
+      int i=0;
+      int foo=begin;
+      while(true){
+        if((i=(inend-instart))<length){
+          if(i!=0){
+            System.arraycopy(inbuffer, instart, array, begin, i);
+            begin+=i;
+            length-=i;
+            instart+=i;
+          }
+          read(length);
+          continue;
+        }
+        System.arraycopy(inbuffer, instart, array, begin, length);
+        instart+=length;
+        break;
+      }
+      return begin+length-foo;
+    }
+
+    int getShort() throws java.io.IOException{
+      if((inend-instart)<2){
+        read(2);
+      }
+      int s=0;
+      s=inbuffer[instart++]&0xff;
+      s=((s<<8)&0xffff)|(inbuffer[instart++]&0xff);
+      return s;
+    }
+
+    int getInt() throws java.io.IOException{
+      if((inend-instart)<4){
+        read(4);
+      }
+      int i=0;
+      i=inbuffer[instart++]&0xff;
+      i=((i<<8)&0xffff)|(inbuffer[instart++]&0xff);
+      i=((i<<8)&0xffffff)|(inbuffer[instart++]&0xff);
+      i=(i<<8)|(inbuffer[instart++]&0xff);
+      return i;
+    }
+
+    void getPad(int n) throws java.io.IOException{
+      int i;
+      while(n>0){
+        if((i=inend-instart)<n){
+          n-=i;
+          instart+=i;
+          read(n);
+          continue;
+        }
+        instart+=n;
+        break;
+      }
+    }
+
+    void read(int n) throws java.io.IOException{
+      if(n>inbuffer.length){
+        n=inbuffer.length;
+      }
+      instart=inend=0;
+      int i;
+      while(true){
+        recpacket.setData(buf, 0, 1024);
+        socket.receive(recpacket);
+
+        i=recpacket.getLength();
+        System.arraycopy(recpacket.getData(), 0, inbuffer, inend, i);
+        if(i==-1){
+          throw new java.io.IOException();
+        }
+        inend+=i;
+        break;
+      }
+    }
+
+	  
+	public void close() throws java.io.IOException{
+      socket.close();
+    }
+
+    public int read() throws java.io.IOException{
+      return 0;
+    }
+
+    public int read(byte[] array, int begin, int length)
+        throws java.io.IOException{
+      return getByte(array, begin, length);
+    }
+  }
+
+  public static void main(String[] arg){
+
+    JFrame frame=new JFrame("AudioPlayer");
+    frame.setBackground(Color.lightGray);
+    frame.setBackground(Color.white);
+    frame.getContentPane().setLayout(new BorderLayout());
+
+    frame.addWindowListener(new WindowAdapter(){
+      public void windowClosing(WindowEvent e){
+        System.exit(0);
+      }
+    });
+
+    AudioPlayer player=new AudioPlayer();
+    player.running_as_applet=false;
+
+    if(arg.length>0){
+      for(int i=0; i<arg.length; i++){
+        player.playlist.addElement(arg[i]);
+      }
+    }
+
+    player.loadPlaylist();
+    player.initUI();
+
+    frame.getContentPane().add(player.panel);
+    frame.pack();
+    frame.setVisible(true);
+  }
+}

Added: trunk/rhea/com/meviatronic/zeus/castor/AudioReader.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/castor/AudioReader.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/castor/AudioReader.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,1036 @@
+/* Castor, a fast Vorbis decoder created by Michael Scheerer.
+ *
+ * Castor decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.castor;
+
+import com.meviatronic.zeus.helen.*;
+import org.xiph.ogg.*;
+
+import java.io.*;
+
+/**
+ * The <code>AudioReader</code> class provides all necessary audio format detection related methods.
+ * The <code>AudioReader</code> class stors also audio header related data.
+ *
+ * @author	Michael Scheerer
+ */
+public class AudioReader {
+	
+	public final static int BITMASK[] = {
+		0x00000000,
+		0x00000001, 0x00000003, 0x00000007, 0x0000000F,
+		0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
+		0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
+		0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
+		0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
+		0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
+		0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
+		0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
+	};
+
+	protected final static int BYTELENGTH = 8;
+	protected final static int DOUBLE_BYTELENGTH = 16;
+	protected final static int TRIPLE_BYTELENGTH = 24;
+	protected final static int QUADRUPEL_BYTELENGTH = 32;
+	
+	private final static int VORBIS_CODEBOOK_SYNC_PATTERN = 0x564342;
+	
+	public int version;
+  	public int channels;
+	public int sampleRate;
+	public int bitRateMax  ;
+  	public int bitRate;
+	public int bitRateMin;
+	
+	private int byteIdx;
+	private byte[] data;
+	private int revBitIdx;
+	private int packetByteIdx;
+	private int packetSize;
+	
+	// Vorbis extendet header
+	private HuffTreeEntry[] hts;
+	private int[] codebookCodewordLengths;
+	
+	int[] codebookDimensions;
+	float[][] valueVector;
+	int[] blocksizes = new int[2];
+	int[] vorbisFloorTypes;
+	int[] floor1Multiplieres;
+	int[][] floor1PartitionClassList;
+	int[][] floor1ClassDimensions;
+	int[][] floor1ClassSubclasses;
+	int[][] floor1ClassMasterbooks;
+	int[][] floor1XList;
+	int floor1MaximumValues;
+	int[][][] floor1SubclassBooks;
+	int[] vorbisResidueTypes;
+	int[] residueMaximumPasses;
+	int[] residueBegin;
+	int[] residueEnd;
+	int[] residuePartitionSize;
+	int[] residueClassifications;
+	int[] residueClassbooks;
+	int[][] residueCascade;
+	int[][][] residueBooks;
+	int[][] vorbisMappingMagnitude;
+	int[][] vorbisMappingAngle;
+	int[][] vorbisMappingMux;
+	int[][] vorbisMappingSubmapFloor;
+	int[][] vorbisMappingSubmapResidue;
+	int[] vorbisModeBlockflag;
+	int[] vorbisModeWindowtype;
+	int[] vorbisModeTransformtype;
+	int[] vorbisModeMapping;
+	int modeNumberBits;
+	
+	private Tag tag;
+
+	private boolean vbr;
+    
+	public void loadPacket(byte[] buf, int start, int bytes){
+		byteIdx = start;
+		data = buf;
+		revBitIdx = packetByteIdx = 0;
+		packetSize = bytes;
+	}
+	
+  	private void verifyFirstPacket() throws IOException, EndOfPacketException {
+		if (getLittleEndian(32) != 0) {
+			throw new InterruptedIOException("Vorbis version not 0");
+		}
+		channels = getLittleEndian(8);
+		sampleRate = getLittleEndian(32);
+		int bitRateMax = getLittleEndian(32);
+		bitRate = getLittleEndian(32);
+		int bitRateMin = getLittleEndian(32);
+			
+		vbr = true;
+		if (!(bitRateMax == bitRateMin && bitRateMax  == bitRate)) {
+			vbr = false;
+		}
+		blocksizes[0] = getLittleEndian(4);
+		blocksizes[1] = getLittleEndian(4);
+			
+		if (blocksizes[0] == 0 || blocksizes[1] == 0 || blocksizes[0] > 13 || blocksizes[1] > 13 || blocksizes[1] < blocksizes[0]) {
+			throw new InterruptedIOException("Wrong block size");
+		}
+		blocksizes[0] = 1 << blocksizes[0];
+		blocksizes[1] = 1 << blocksizes[1];
+		if (getLittleEndian1() == 0) {
+			throw new InterruptedIOException("Wrong framing bit");
+		}
+		if (channels == 0 || channels > 2) {
+			throw new InterruptedIOException("Wrong number of channels");
+		}
+		if (sampleRate > 48000 || sampleRate == 0) {
+			throw new InterruptedIOException("Wrong sample rate");
+		}
+		if (bitRate == 0) {
+			if (bitRateMax > 0 & bitRateMin > 0) {
+				bitRate = (bitRateMax + bitRateMin) / 2;
+			} else if (bitRateMax > 0) {
+				bitRate = bitRateMax;
+			} else if (bitRateMax > 0) {
+				bitRate = bitRateMin;
+			}
+		}
+  	}
+	
+	private final void verifySecondPacket() throws IOException, EndOfPacketException {
+		try {
+			tag = new OggTag(this, true);
+			((OggTag) tag).decode();
+		} catch (Exception e) {
+			if (e instanceof IOException) {
+				throw new InterruptedIOException(e.getMessage());
+			}
+		}
+	}
+	
+	private final void verifyThirdPacket() throws IOException, EndOfPacketException {
+		int i, j, k;
+		
+		// 4.2.4.1. Codebooks
+
+		int vorbisCodebookCount = getLittleEndian(8) + 1;
+		
+		codebookDimensions = new int[vorbisCodebookCount];
+		hts = new HuffTreeEntry[vorbisCodebookCount];
+		valueVector = new float[vorbisCodebookCount][];
+		float[] valueVectorPointer = null;
+		
+		for (i = 0; i < vorbisCodebookCount; i++) {
+
+			if (getLittleEndian(24) != VORBIS_CODEBOOK_SYNC_PATTERN) {
+				throw new InterruptedIOException("Broken codebook sync pattern");
+			}
+		
+			int codebookDimension = getLittleEndian(16);
+			codebookDimensions[i] = codebookDimension;
+			int codebookEntries = getLittleEndian(24);
+			
+			int usedEntries = 0;
+			int ordered = getLittleEndian1();
+			codebookCodewordLengths = new int[codebookEntries];
+			int currentLength = 0;
+			int maxLength = 0;
+			int currentEntry = 0;
+
+			if (ordered == 0) {
+				int sparse = getLittleEndian1();
+				int flag;
+			
+				for (j = 0; j < codebookEntries; j++) {
+					if(sparse == 1) {
+						flag = getLittleEndian1();
+						if(flag == 1) {
+							currentLength = codebookCodewordLengths[j] = getLittleEndian(5) + 1;
+						}
+					} else {
+						currentLength = codebookCodewordLengths[j] = getLittleEndian(5) + 1;
+					}
+					if (currentLength > maxLength) {
+						maxLength = currentLength;
+					}
+				}
+			} else {
+				currentLength = getLittleEndian(5) + 1;
+				int number;
+				int end;
+			
+				if (currentLength > maxLength) {
+					maxLength = currentLength;
+				}
+				do {
+					number = getLittleEndian(ilog(codebookEntries - currentEntry));
+					end = currentEntry + number;
+			
+					for (j = currentEntry; j < end; j++) {
+						codebookCodewordLengths[j] = currentLength;
+					}
+					currentEntry = number + currentEntry;
+					currentLength++;
+					if (currentEntry > codebookEntries) {
+						throw new InterruptedIOException("Codebook overflow");
+					}
+					if (currentLength > maxLength) {
+						maxLength = currentLength;
+					}
+				} while (currentEntry < codebookEntries);
+			}
+			
+			for (j = 0; j < codebookEntries; j++) {
+				if(codebookCodewordLengths[j] > 0) {
+					usedEntries++;
+					currentEntry = j;
+				}
+			}
+
+			HuffTreeEntry node = null;
+			
+			if (usedEntries == 1) {
+				node = new HuffTreeEntry();
+				
+				node.sparse = true;
+				node.value = currentEntry;
+			} else if (usedEntries > 1) {
+				node = new HuffTreeEntry();
+				
+				buildTree(node, maxLength);
+				deflateTree(node);
+				pruneTree(node);
+			}
+
+			hts[i] = node;
+			
+			int codebookLookupType = getLittleEndian(4);
+			
+			if (codebookLookupType > 2) {
+				throw new InterruptedIOException("Code lookup type overflow");
+			} else if (codebookLookupType == 0) {
+				// Lookup type zero indicates no lookup to be read. Proceed past lookup decode.
+				if (valueVectorPointer == null) {
+					valueVector[i] = new float[codebookDimension * codebookEntries];
+				} else {
+					valueVector[i] = valueVectorPointer;
+				}
+				continue;
+			}
+			
+			float codebookMinimumValue = float32Unpack(getLittleEndian(32));
+			float codebookDeltaValue = float32Unpack(getLittleEndian(32));
+			int codebookValueBits = getLittleEndian(4) + 1;
+			int codebookSequenceP = getLittleEndian1();
+			int codebookLookupValues = 0;
+			
+			if (codebookLookupType == 1) {
+				codebookLookupValues = (int) Math.floor(Math.pow(codebookEntries, 1F / codebookDimension));
+			} else {
+				codebookLookupValues = codebookEntries * codebookDimension;
+			}
+			
+			int[] codebookMultiplicands = new int[codebookLookupValues];
+			
+			for (j = 0; j < codebookLookupValues; j++) {
+				codebookMultiplicands[j] = getLittleEndian(codebookValueBits);
+			}
+			
+			if (usedEntries == 0) {
+				continue;
+			}
+
+			float last;
+			int indexDivisor;
+			int multiplicandOffset;
+			valueVectorPointer = new float[codebookDimension * codebookEntries];
+			float valueVectorContent = 0;
+			
+			if (codebookLookupType == 1) {
+				for (j = 0; j < codebookEntries; j++) {
+					last = 0;
+					indexDivisor = 1;
+				
+					for (k = 0; k < codebookDimension; k++) {
+						multiplicandOffset = (j / indexDivisor) % codebookLookupValues;
+						valueVectorContent = codebookMultiplicands[multiplicandOffset] * codebookDeltaValue + codebookMinimumValue + last;
+						if (codebookSequenceP == 1) {
+							last = valueVectorContent;
+						}
+						valueVectorPointer[j * codebookDimension + k] = valueVectorContent;
+						indexDivisor *= codebookLookupValues;
+					}
+				}
+			} else {
+				for (j = 0; j < codebookEntries; j++) {
+					last = 0;
+					multiplicandOffset = j * codebookDimension;
+				
+					for (k = 0; k < codebookDimension; k++) {
+						valueVectorContent = codebookMultiplicands[multiplicandOffset + k] * codebookDeltaValue + codebookMinimumValue + last;
+
+						if (codebookSequenceP == 1) {
+							last = valueVectorContent;
+						}
+						valueVectorPointer[multiplicandOffset + k] = valueVectorContent;
+					}
+				}
+			}
+			valueVector[i] = valueVectorPointer;
+		}
+		
+		codebookCodewordLengths = null;
+		
+		// 4.2.4.2. Time domain transforms
+
+		int vorbisTimeCount = getLittleEndian(6) + 1;
+		
+		for (i = 0; i < vorbisTimeCount; i++) {
+			if (getLittleEndian(16) != 0) {
+				throw new IOException("Unexcepted end of time domain setup");
+			}
+		}
+		
+		// 4.2.4.3. Floors
+		
+		int vorbisFloorCount = getLittleEndian(6) + 1;
+	
+		vorbisFloorTypes = new int[vorbisFloorCount];
+		int vorbisFloorTyp;
+		int floor1Partitions;
+		int maximumClass;
+		int floor1PartitionClass;
+		int floor1ClassSubclass;
+		int floor1SubclassRange;
+		int floor1Multiplier;
+		int rangebits;
+		int floor1Values;
+		int floor1ClassDimensionsElement;
+		floor1Multiplieres = new int[vorbisFloorCount];
+		floor1PartitionClassList = new int[vorbisFloorCount][];
+		floor1ClassDimensions = new int[vorbisFloorCount][];
+		floor1ClassSubclasses = new int[vorbisFloorCount][];
+		floor1ClassMasterbooks = new int[vorbisFloorCount][];
+		floor1SubclassBooks = new int[vorbisFloorCount][][];
+		floor1XList = new int[vorbisFloorCount][];
+		
+		for (i = 0; i < vorbisFloorCount; i++) {
+			vorbisFloorTyp = getLittleEndian(16);
+			if (vorbisFloorTyp == 0 || vorbisFloorTyp > 1) {
+				throw new IOException("No support of floor type zero or wrong floor type");
+			}
+			floor1Partitions = getLittleEndian(5);
+			floor1PartitionClassList[i] = new int[floor1Partitions];
+			maximumClass = -1;
+			
+			for (j = 0; j < floor1Partitions; j++) {
+				floor1PartitionClass = getLittleEndian(4);
+				if (floor1PartitionClass > maximumClass) {
+					maximumClass = floor1PartitionClass;
+				}
+				floor1PartitionClassList[i][j] = floor1PartitionClass;
+			}
+
+			int[] dimensions = floor1ClassDimensions[i] = new int[maximumClass + 1];
+			int[] subclasses = floor1ClassSubclasses[i] = new int[maximumClass + 1];
+			int[] masterbooks = floor1ClassMasterbooks[i] = new int[maximumClass + 1];
+			int[][] subclassbooks = floor1SubclassBooks[i] = new int[maximumClass + 1][];
+			
+			for (j = 0; j < maximumClass + 1; j++) {
+				dimensions[j] = getLittleEndian(3) + 1;
+				floor1ClassSubclass = getLittleEndian(2);
+				
+				if (floor1ClassSubclass != 0) {
+					if ((masterbooks[j] = getLittleEndian(8)) >= vorbisCodebookCount) {
+						throw new IOException("Number of classbooks can't be GE than number of huffman books");
+					}
+				}
+				subclasses[j] = floor1ClassSubclass;
+				
+				floor1SubclassRange = 1 << floor1ClassSubclass;
+				
+				subclassbooks[j] = new int[floor1SubclassRange];
+				
+				for (k = 0; k < floor1SubclassRange; k++) {
+					if ((subclassbooks[j][k] = getLittleEndian(8) - 1) >= vorbisCodebookCount) {
+						throw new IOException("Number of floor subclass books can't be GE than number of huffman books");
+					}
+				}
+			}
+
+			floor1Multiplier = getLittleEndian(2) + 1;
+			rangebits = getLittleEndian(4);
+			floor1Values = 2;
+			
+			int[] floor1ClassDimensionsElementTable = new int[floor1Partitions];
+			
+			for (j = 0; j < floor1Partitions; j++) {
+				floor1ClassDimensionsElementTable[j] = floor1ClassDimensionsElement = floor1ClassDimensions[i][floor1PartitionClassList[i][j]];
+				floor1Values += floor1ClassDimensionsElement;
+			}
+
+			floor1XList[i] = new int[floor1Values];
+			if (floor1Values > floor1MaximumValues) {
+				floor1MaximumValues = floor1Values;
+			}
+			floor1XList[i][0] = 0;
+			floor1XList[i][1] = 1 << rangebits;
+			floor1Values = 2;
+			
+			for (j = 0; j < floor1Partitions; j++) {
+				floor1ClassDimensionsElement = floor1ClassDimensionsElementTable[j];
+				
+				for (k = 0; k < floor1ClassDimensionsElement; k++) {
+					if ((floor1XList[i][floor1Values] = getLittleEndian(rangebits)) >= 1 << rangebits) {
+						throw new IOException("Floor book values can't be GE than 1 << rangebits");
+					}
+					floor1Values++;
+				}
+			}
+			vorbisFloorTypes[i] = vorbisFloorTyp;
+			floor1Multiplieres[i] = floor1Multiplier;
+		}
+
+		// 4.2.4.4. Residues
+		
+		int vorbisResidueCount = getLittleEndian(6) + 1;
+		
+		vorbisResidueTypes = new int[vorbisResidueCount];
+		residueBegin = new int[vorbisResidueCount];
+		residueEnd = new int[vorbisResidueCount];
+		residuePartitionSize = new int[vorbisResidueCount];
+		residueClassifications = new int[vorbisResidueCount];
+		residueClassbooks = new int[vorbisResidueCount];
+		residueMaximumPasses = new int[vorbisResidueCount];
+		
+		int residueCascadeEntry;
+		int classifications;
+		int typeEntry;
+		int maximumPassesEntry;
+		int passes;
+       	
+		residueCascade = new int[vorbisResidueCount][];
+		residueBooks = new int[vorbisResidueCount][][];
+		
+		for (i = 0; i < vorbisResidueCount; i++) {
+			maximumPassesEntry = 0;
+			typeEntry = getLittleEndian(16);
+			if (typeEntry > 2) {
+				throw new IOException("No support of residue type greater 2");
+			} else {
+				vorbisResidueTypes[i] = typeEntry;
+				residueBegin[i] = getLittleEndian(24);
+				residueEnd[i] = getLittleEndian(24);
+				residuePartitionSize[i] = getLittleEndian(24) + 1;
+				classifications = residueClassifications[i] = getLittleEndian(6) + 1;
+				
+				if ((residueClassbooks[i] = getLittleEndian(8)) >= vorbisCodebookCount) {
+					throw new IOException("Number of residue class books can't be greater than number of huffman books");
+				}
+
+				int[] cascade = residueCascade[i] = new int[classifications];
+				int[][] book = residueBooks[i] = new int[classifications][];
+				
+				for (j = 0; j < classifications; j++) {
+					residueCascadeEntry = getLittleEndian(3);
+					if (getLittleEndian1() == 1) {
+       					residueCascadeEntry |= getLittleEndian(5) << 3;
+					}
+					passes = ilog(residueCascadeEntry);
+					if (maximumPassesEntry < passes) {
+						maximumPassesEntry = passes;
+					}
+					book[j] = new int[passes];
+					cascade[j] = residueCascadeEntry;
+				}
+
+				residueMaximumPasses[i] = maximumPassesEntry;;
+
+				for (j = 0; j < classifications; j++) {
+					for (k = 0; k < book[j].length; k++) {
+						if ((cascade[j] & 1 << k) != 0) {
+							if ((book[j][k] = getLittleEndian(8)) >= vorbisCodebookCount) {
+								throw new IOException("Number of residue books can't be greater than number of huffman books");
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		// 4.2.4.5. Mappings
+		
+		int vorbisMappingCount = getLittleEndian(6) + 1;
+		int vorbisMappingSubmaps;
+		int vorbisMappingSubmapsMax = -1;
+		int vorbisMappingCouplingSteps;
+		vorbisMappingMagnitude = new int[vorbisMappingCount][];
+		vorbisMappingAngle = new int[vorbisMappingCount][];
+		vorbisMappingMux = new int[vorbisMappingCount][channels];
+		vorbisMappingSubmapFloor = new int[vorbisMappingCount][];
+		vorbisMappingSubmapResidue = new int[vorbisMappingCount][];
+		int vorbisMappingMagnitudeEntry;
+		int vorbisMappingAngleEntry;
+		
+		for (i = 0; i < vorbisMappingCount; i++) {
+			if (getLittleEndian(16) != 0) {
+				throw new IOException("Wrong mapping type");
+			}
+			if (getLittleEndian1() == 1) {
+				vorbisMappingSubmaps = getLittleEndian(4) + 1;
+			} else {
+				vorbisMappingSubmaps = 1;
+			}
+			if (vorbisMappingSubmaps > vorbisMappingSubmapsMax) {
+				vorbisMappingSubmapsMax = vorbisMappingSubmaps;
+			}
+			if (getLittleEndian1() == 1) {
+				vorbisMappingCouplingSteps = getLittleEndian(8) + 1;
+				vorbisMappingMagnitude[i] = new int[vorbisMappingCouplingSteps];
+				vorbisMappingAngle[i] = new int[vorbisMappingCouplingSteps];
+				
+				for (j = 0; j < vorbisMappingCouplingSteps; j++) {
+					vorbisMappingMagnitudeEntry = getLittleEndian(ilog(channels - 1));
+					vorbisMappingAngleEntry = getLittleEndian(ilog(channels - 1));
+					if (vorbisMappingMagnitudeEntry == vorbisMappingAngleEntry || vorbisMappingMagnitudeEntry >= channels || vorbisMappingAngleEntry >= channels) {
+						throw new IOException("Wrong channel mapping");
+					}
+					
+					vorbisMappingMagnitude[i][j] = vorbisMappingMagnitudeEntry;
+					vorbisMappingAngle[i][j] = vorbisMappingAngleEntry;
+				}
+			} else {
+				vorbisMappingCouplingSteps = 0;
+			}
+			if (getLittleEndian(2) != 0) {
+				throw new IOException("Reserved bits should be zero");
+			}
+			if (vorbisMappingSubmaps > 1) {
+				for (j = 0; j < channels; j++) {
+					if ((vorbisMappingMux[i][j] = getLittleEndian(4)) >= vorbisMappingSubmapsMax) {
+						throw new IOException("Wrong channel mapping mux");
+					}
+				}
+			}
+			
+			int[] floor = vorbisMappingSubmapFloor[i] = new int[vorbisMappingSubmaps];
+			int[] residue = vorbisMappingSubmapResidue[i] = new int[vorbisMappingSubmaps];
+			
+			for (j = 0; j < vorbisMappingSubmaps; j++) {
+				skipLittleEndian(8);
+				if ((floor[j] = getLittleEndian(8)) >= vorbisFloorCount) {
+					throw new IOException("Wrong floor mapping number");
+				}
+				if ((residue[j] = getLittleEndian(8)) >= vorbisResidueCount) {
+					throw new IOException("Wrong residue mapping number");
+				}
+			}
+		}
+		
+		// 4.2.4.6. Modes
+		
+		int vorbisModeCount = getLittleEndian(6) + 1;
+		modeNumberBits = ilog(vorbisModeCount - 1);
+		vorbisModeBlockflag = new int[vorbisModeCount];
+		vorbisModeWindowtype = new int[vorbisModeCount];
+		vorbisModeTransformtype = new int[vorbisModeCount];
+		vorbisModeMapping = new int[vorbisModeCount];
+		
+		for (i = 0; i < vorbisModeCount; i++) {
+			vorbisModeBlockflag[i] = getLittleEndian1();
+			if ((vorbisModeWindowtype[i] = getLittleEndian(16)) > 0) {
+				throw new IOException("Wrong mode window type");
+			}
+			if ((vorbisModeTransformtype[i] = getLittleEndian(16)) > 0) {
+				throw new IOException("Wrong mode transform type");
+			}
+			if ((vorbisModeMapping[i] = getLittleEndian(8)) >= vorbisMappingCount) {
+				throw new IOException("Wrong mode mapping number");
+			}
+		}
+		if (getLittleEndian1() == 0) {
+			throw new IOException("Framing bit error");
+		}
+	}
+
+	public void readMediaInformation(Packet op) throws IOException, EndOfPacketException {
+
+		if(op == null) {
+			throw new InterruptedIOException("Packet is null");
+		}
+
+		loadPacket(op.packetBase, op.packet, op.bytes);
+		
+		byte[] buffer = new byte[6];
+		
+		int packetType = getLittleEndian(8);
+			
+		for (int i = 0; i < buffer.length; i++) {
+			buffer[i] = (byte) getLittleEndian(8);
+		}
+		
+		if (!new String(buffer).equals("vorbis")) {
+			throw new InterruptedIOException("No first packet");
+		}
+	
+		if (packetType == 0x01 && op.bos != 0) {
+			verifyFirstPacket();
+		} else if (packetType == 0x03 && op.bos == 0) {
+			verifySecondPacket();
+		} else if (packetType == 0x05 && op.bos == 0) {
+			verifyThirdPacket();
+		} else {
+			throw new InterruptedIOException("Wrong packet order");
+		}
+	}
+	
+	/**
+	 * Returns one bit
+	 *
+	 * @return                               the integer value
+	 * @exception EndOfPacketExeption        if an end of packet occur
+	 */
+	public final int getLittleEndian1() throws EndOfPacketException {
+		if (packetByteIdx >= packetSize) {
+			throw new EndOfPacketException();
+		}
+
+		int val = data[byteIdx] >>> revBitIdx & 1;
+
+		revBitIdx++;
+		if (revBitIdx == BYTELENGTH) {
+			revBitIdx = 0;
+			byteIdx++;
+			packetByteIdx++;
+		}
+
+		return val;
+	}
+	
+	/**
+	 * Returns an integer with the length i
+	 *
+	 * @return                               the integer value
+	 * @param i                              the length in bits
+	 * @exception EndOfPacketExeption        if an end of packet occur
+	 */
+	public final int getLittleEndian(int i) throws EndOfPacketException {
+		if (i <= 0) {
+			return 0;
+		}
+		if (packetByteIdx >= packetSize) {
+			throw new EndOfPacketException();
+		}
+
+		int store = revBitIdx;
+		
+		int val = (data[byteIdx] & 0xFF) >>> store;
+		
+		revBitIdx += i;
+		
+		if (revBitIdx >= BYTELENGTH) {
+			byteIdx++;
+			if (++packetByteIdx >= packetSize) {
+				throw new EndOfPacketException();
+			}
+			val |= (data[byteIdx] & 0xFF) << BYTELENGTH - store;
+			if (revBitIdx >= DOUBLE_BYTELENGTH) {
+				byteIdx++;
+				if (++packetByteIdx >= packetSize) {
+					throw new EndOfPacketException();
+				}
+				val |= (data[byteIdx] & 0xFF) << DOUBLE_BYTELENGTH - store;
+				if (revBitIdx >= TRIPLE_BYTELENGTH) {
+					byteIdx++;
+					if (++packetByteIdx >= packetSize) {
+						throw new EndOfPacketException();
+					}
+					val |= (data[byteIdx] & 0xFF) << TRIPLE_BYTELENGTH - store;
+					if (revBitIdx >= QUADRUPEL_BYTELENGTH) {
+						byteIdx++;
+						if (++packetByteIdx >= packetSize) {
+							throw new EndOfPacketException();
+						}
+						val |= ((data[byteIdx] & 0xFF) << QUADRUPEL_BYTELENGTH - store) & 0xFF000000;
+					}
+				}
+			}
+			revBitIdx &= 7;
+		}
+		return val & BITMASK[i];
+	}
+	
+	final void skipLittleEndian(int j) throws EndOfPacketException {
+		if (packetByteIdx >= packetSize) {
+			throw new EndOfPacketException();
+		}
+		revBitIdx += j;
+		while (revBitIdx >= BYTELENGTH) {
+			revBitIdx -= BYTELENGTH;
+			byteIdx++;
+			if (++packetByteIdx >= packetSize) {
+				throw new EndOfPacketException();
+			}
+		}
+	}
+
+	public final static int ilog(int v) {
+    	int ret = 0;
+		
+		while (v != 0) {
+			ret++;
+			v >>>= 1;
+		}
+		return ret;
+	}
+	
+	private static float float32Unpack(int x) {
+		int mantissa = x & 0x1FFFFF;
+		int exponent = (x & 0x7FE00000) >>> 21;
+		
+		if ((x & 0x80000000) != 0) {
+			mantissa = -mantissa;
+		}
+		return (float) (mantissa * Math.pow(2, exponent - 788));
+	}
+
+  	public String getOggCommentContent() {
+		return tag.toString();
+	}
+	
+	final int getCodeWord(int bookNumber) throws IOException, EndOfPacketException {
+		
+		HuffTreeEntry node = hts[bookNumber];
+		
+		if (node == null) {
+			throw new IOException("Unexcepted end of codebook");
+		}
+		if (node.sparse) {
+			return node.value;
+		}
+		while (node.value == -1) {
+			node = node.childFeed[getLittleEndian(node.feed)];
+			if (node == null) {
+				throw new IOException("Unexcepted end of codebook");
+			}
+		}
+		return node.value;
+	}
+
+	final boolean bookIsUnused(int bookNumber) {
+		return hts[bookNumber] == null ? true : false;
+	}
+
+	/**
+	 * Frees all system resources, which are bounded to this object.
+	 */
+	public void close() {
+		int i, j;
+		
+		if (hts != null) {
+			for (i = 0; i < hts.length; i++) {
+				if (hts[i] != null) {
+					closeTree(hts[i]);
+				}
+				hts[i] = null;
+			}
+		} else {
+			return;
+		}
+		tag.close();
+		tag = null;
+		
+		hts = null;
+		data = null;
+		blocksizes = null;
+		for (i = 0; i < valueVector.length; i++) {
+			valueVector[i] = null;
+		}
+		valueVector = null;
+		codebookDimensions = null;
+		vorbisFloorTypes = null;
+		floor1Multiplieres = null;
+		for (i = 0; i < floor1PartitionClassList.length; i++) {
+			floor1PartitionClassList[i] = null;
+		}
+		floor1PartitionClassList = null;
+		for (i = 0; i < floor1ClassDimensions.length; i++) {
+			floor1ClassDimensions[i] = null;
+		}
+		floor1ClassDimensions = null;
+		for (i = 0; i < floor1ClassSubclasses.length; i++) {
+			floor1ClassSubclasses[i] = null;
+		}
+		floor1ClassSubclasses = null;
+		for (i = 0; i < floor1ClassMasterbooks.length; i++) {
+				floor1ClassMasterbooks[i] = null;
+		}
+		floor1ClassMasterbooks = null;
+		for (i = 0; i < floor1XList.length; i++) {
+			floor1XList[i] = null;
+		}
+		floor1XList = null;
+		
+		int[][] pointer;
+		
+		for (i = 0; i < floor1SubclassBooks.length; i++) {
+			pointer = floor1SubclassBooks[i];
+			for (j = 0; j < pointer.length; j++) {
+				pointer[j] = null;
+			}
+			pointer = null;
+		}
+		floor1SubclassBooks = null;
+		vorbisResidueTypes = null;
+		residueMaximumPasses = null;
+		residueBegin = null;
+		residueEnd = null;
+		residuePartitionSize = null;
+		residueClassifications = null;
+		residueClassbooks = null;
+		for (i = 0; i < residueCascade.length; i++) {
+			residueCascade[i] = null;
+		}
+		residueCascade = null;
+		for (i = 0; i < residueBooks.length; i++) {
+			pointer = residueBooks[i];
+			for (j = 0; j < pointer.length; j++) {
+				pointer[j] = null;
+			}
+			pointer = null;
+		}
+		residueBooks = null;
+		for (i = 0; i < vorbisMappingMagnitude.length; i++) {
+			vorbisMappingMagnitude[i] = null;
+		}
+		vorbisMappingMagnitude = null;
+		for (i = 0; i < vorbisMappingAngle.length; i++) {
+			vorbisMappingAngle[i] = null;
+		}
+		vorbisMappingAngle = null;
+		for (i = 0; i < vorbisMappingMux.length; i++) {
+			vorbisMappingMux[i] = null;
+		}
+		vorbisMappingMux = null;
+		for (i = 0; i < vorbisMappingSubmapFloor.length; i++) {
+			vorbisMappingSubmapFloor[i] = null;
+		}
+		vorbisMappingSubmapFloor = null;
+		for (i = 0; i < vorbisMappingSubmapResidue.length; i++) {
+			vorbisMappingSubmapResidue[i] = null;
+		}
+		vorbisMappingSubmapResidue = null;
+		vorbisModeBlockflag = null;
+		vorbisModeWindowtype = null;
+		vorbisModeTransformtype = null;
+		vorbisModeMapping = null;
+	}
+	
+	private void deflateTree(HuffTreeEntry node) throws IOException {
+		int i, j, k, l, r, feedMinusOne, feedMinusOneMinusJ;
+		HuffTreeEntry nodeBase = node, nodeVerify;
+			
+		for (node.feed = 2; node.feed < 33; node.feed++) {
+			k = 1 << node.feed;
+			HuffTreeEntry[] copy = new HuffTreeEntry[k];
+			
+			feedMinusOne = node.feed - 1;
+			for (i = 0; i < k; i++) {
+				for (j = 0; j < node.feed; j++) {
+					feedMinusOneMinusJ = feedMinusOne - j;
+					l = (i & 1 << feedMinusOneMinusJ) >>> feedMinusOneMinusJ;
+					nodeVerify = nodeBase.child[l ^ 1];
+					nodeBase = nodeBase.child[l];
+					if (nodeBase == null) {
+						node.feed--;
+						copy = null;
+						if (node.feed > 1) {
+							for (i = 0; i < node.childFeed.length; i++) {
+								deflateTree(node.childFeed[i]);
+							}
+						}
+						return;
+					}
+					if (nodeVerify == null) {
+						throw new InterruptedIOException("Underpopulated tree");
+					}
+				}
+				r = 0;
+				for (j = 0; j < node.feed; j++) {
+					r <<= 1;
+					r |= i >>> j & 1;
+				}
+				copy[r] = nodeBase;
+				nodeBase = node;
+			}
+			for (i = 0; i < node.childFeed.length; i++) {
+				node.childFeed[i].dereferenced = true;
+			}
+			node.childFeed = copy;
+		}
+	}
+	
+	private void buildTree(HuffTreeEntry node, int maxLength) throws IOException {
+		int i, j;
+		int shiftedNodeCount;
+		int limit = maxLength + 1;
+		int[] shiftedNodeCounts = new int[limit];
+		int currentLength;
+		int currentValue;
+		HuffTreeEntry nodeBase = node;
+			
+		for (i = 0; i < codebookCodewordLengths.length; i++) {
+			if ((currentLength = codebookCodewordLengths[i]) == 0) {
+				continue;
+			}
+			currentValue = shiftedNodeCount = shiftedNodeCounts[currentLength];
+			if (shiftedNodeCount >>> currentLength != 0) {
+				throw new InterruptedIOException("Overpopulated tree");
+			}
+			for (j = currentLength; j > 0; j--) {
+				if ((shiftedNodeCounts[j] & 1) != 0) {
+					if (j == 1) {
+						shiftedNodeCounts[1]++;
+					} else {
+						shiftedNodeCounts[j] = shiftedNodeCounts[j - 1] << 1;
+					}
+					break;
+				}
+				shiftedNodeCounts[j]++;
+			}
+			for (j = currentLength + 1; j < limit; j++) {
+				if ((shiftedNodeCounts[j] >>> 1) == shiftedNodeCount) {
+					shiftedNodeCount = shiftedNodeCounts[j];
+					shiftedNodeCounts[j] = shiftedNodeCounts[j - 1] << 1;
+				} else {
+					break;
+				}
+			}
+			for (j = currentLength - 1; j >= 0; j--) {
+				if ((currentValue >>> j & 0x1) == 1) {
+					if (nodeBase.child[1] == null) {
+						nodeBase.child[1] = new HuffTreeEntry();
+					}
+					nodeBase = nodeBase.child[1];
+				} else {
+					if (nodeBase.child[0] == null) {
+						nodeBase.child[0] = new HuffTreeEntry();
+					}
+					nodeBase = nodeBase.child[0];
+				}
+			}
+			nodeBase.value = i;
+			nodeBase = node;
+		}
+	}
+
+	private void pruneTree(HuffTreeEntry node) {
+		HuffTreeEntry left = node.child[0];
+		HuffTreeEntry right = node.child[1];
+		
+		if (left != null) {
+			pruneTree(left);
+			pruneTree(right);
+		}
+		if (node.dereferenced) {
+			node.child = null;
+			node = null;
+		} else {
+			if (node.child != node.childFeed) {
+				node.child = null;
+			}
+		}
+	}
+	
+	private void closeTree(HuffTreeEntry node) {
+		if (node.sparse) {
+			node.child = null;
+			node = null;
+			return;
+		}
+
+		HuffTreeEntry nodeBase;
+		
+		for (int i = 0; i < node.childFeed.length; i++) {
+			nodeBase = node.childFeed[i];
+			if (nodeBase != null) {
+				closeTree(nodeBase);
+				nodeBase = null;
+			}
+		}
+		node.child = null;
+		node.childFeed = null;
+		node = null;
+	}
+	
+	private class HuffTreeEntry {
+		HuffTreeEntry[] child = new HuffTreeEntry[2];
+		HuffTreeEntry[] childFeed = child;
+		int value = -1;
+		boolean sparse;
+		byte feed = 1;
+		boolean dereferenced;
+	}
+}
+

Added: trunk/rhea/com/meviatronic/zeus/castor/EndOfMediaException.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/castor/EndOfMediaException.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/castor/EndOfMediaException.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,45 @@
+/* Castor, a fast Vorbis decoder created by Michael Scheerer.
+ *
+ * Castor decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.castor;
+
+import java.io.*;
+
+/**
+ * This <code>Exception</code> should be thrown if an end of media exception occurs.
+ *
+ * @author    Michael Scheerer
+ */
+public final class EndOfMediaException extends IOException {
+
+	/**
+	 * Constructs an instance of <code>EndOfMediaException</code>.
+	 *
+	 * @param s  the exception message
+	 */
+	public EndOfMediaException(java.lang.String s) {
+		super(s);
+	}
+}
+

Added: trunk/rhea/com/meviatronic/zeus/castor/EndOfPacketException.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/castor/EndOfPacketException.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/castor/EndOfPacketException.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,34 @@
+/* Castor, a fast Vorbis decoder created by Michael Scheerer.
+ *
+ * Castor decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.castor;
+
+/**
+ * This <code>Exception</code> should be thrown if an end of packet exception occurs.
+ *
+ * @author    Michael Scheerer
+ */
+public final class EndOfPacketException extends Exception {
+}
+

Added: trunk/rhea/com/meviatronic/zeus/castor/Imdct.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/castor/Imdct.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/castor/Imdct.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,301 @@
+/* Castor, a fast Vorbis decoder created by Michael Scheerer.
+ *
+ * Castor decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.castor;
+
+/**
+ *  The <code>Imdct</code> class provides an implementation of the inverse MDCT
+ *  based on:
+ *  The use of multirate filter banks for coding of high quality digital audio,
+ *  6th European Signal Processing Conference (EUSIPCO), Amsterdam, June 1992, Vol.1, pages 211-214Th,
+ *  Sporer Kh.Brandenburg B.Edler
+ *
+ *  @author     Michael Scheerer
+ */
+final class Imdct {
+	private float[] A;
+	private float[] AR;
+	private float[] BH;
+	private float[] C;
+	private int[] bitreversedIndex;
+	private int n;
+	private int nHalf;
+	private int nQuarter;
+	private int nThreeFourths;
+	private int nEighth;
+	private int lEnd;
+ 
+	void initialize(int n) {
+	
+		this.n = n;
+		
+		int i, j, k = 0;
+		
+		nHalf = n >>> 1;
+		nQuarter = n >>> 2;
+		nEighth = n >>> 3;
+		nThreeFourths = nQuarter * 3;
+		A = new float[nHalf];
+		AR = new float[nHalf];
+		BH = new float[nHalf];
+		C = new float[nQuarter];
+		bitreversedIndex = new int[nEighth];
+	
+		int log2n = (int) (Math.log(n) / Math.log(2));
+	  
+	  	lEnd = log2n - 3;
+	  
+		int codePattern;
+		
+		for (i = 0; i < nEighth; i++) {
+			codePattern = 0;
+			
+			for (j = 0; j < lEnd; j++) {
+				codePattern <<= 1;
+				codePattern |= i >>> j & 1;
+			}
+			
+			j = codePattern;
+			
+			if (!(i > 0 && i < nEighth - 1)) {
+				j = i;
+			}
+			bitreversedIndex[i] = j;
+		}
+		
+		int nHalfMinusI2Minus1;
+		int nHalfMinusI2Minus2;
+		int i2, i2Plus1;
+		
+	  	for (i = 0; i < nQuarter; i++) {
+		  	i2 = i << 1;
+		  	i2Plus1 = i2 + 1;
+			nHalfMinusI2Minus1 = nHalf - i2 - 1;
+			nHalfMinusI2Minus2 = nHalf - i2 - 2;
+			AR[nHalfMinusI2Minus1] = A[i2] = (float) Math.cos(Math.PI / n * 4 * i);
+			AR[nHalfMinusI2Minus2] = A[i2Plus1] = (float) -Math.sin(Math.PI / n * 4 * i);
+			BH[i2] = (float) Math.cos(Math.PI / (n << 1) * (i << 1 | 1)) / 2;
+			BH[i2Plus1] = (float) Math.sin(Math.PI / (n << 1) * (i << 1 | 1)) / 2;
+		}
+
+	  	for (i = 0; i < nEighth; i++) {
+		  	i2 = i << 1;
+		  	i2Plus1 = i2 + 1;
+			C[i2] = (float) Math.cos(Math.PI / nHalf * (i << 1 | 1));
+			C[i2Plus1] = (float) -Math.sin(Math.PI / nHalf * (i << 1 | 1));
+		}
+	}
+	
+	void decode(float[] in, float[] out, float[] window, float[] floor) {
+		int k, l, r, s;
+		float upOdd, downOdd, upEven, downEven;
+		int upOddIndex, downOddIndex, upEvenIndex, downEvenIndex;
+ 		int i2k, i2kPlus1, i2kPlusNquarter, i2kPlus1PlusNquarter;
+ 		int i4k, i4kr, i4kPlus1, i4kPlus3;
+		int iNquarterMinuskMinus1, iNthreeFourthsMinuskMinus1, iNthreeFourthsPlusk, iNquarterPlusk;
+ 		int iNquarterMinus1 = nQuarter - 1, iNthreeFourthsMinus1 = nThreeFourths - 1;
+ 		int iNhalfMinus1 = nHalf - 1, iNhalfMinus2 = nHalf - 2, iNhalfMinus4 = nHalf - 4;
+ 		int iNhalfMinus4kMinus4, iNhalfMinus4kMinus4r;
+		int iNhalfMinus2Minusr2;
+		int k0, k0Half, k1;
+		int rEnd, sEnd;
+		int rk1;
+		float ark1, ark1Plus1;
+		float ar2k, ar2kPlus1, ar2kPlusNhalf, ar2kPlus1PlusNhalf, ar4k, ar4kPlus1;
+ 		float factor1, factor2, factor3, factor4, factor5, factor6;
+		float base1, base2;
+		float w4k, w4kPlus1, w4kPlus3;
+		float wNhalfMinus4kMinus1, wNhalfMinus4kMinus2, wNhalfMinus4kMinus4;
+		float c2k, c2kPlus1;
+		float bh2k, bh2kPlus1;
+		
+		// First half:
+		// Vn-4k-1 = 2 * (U4k * A2k - U4k+2 * A2k+1)
+		// Vn-4k-3 = 2 * (U4k * A2k+1 + U4k+2 * A2k)
+
+		// Second half:
+		// Vn-4k-1 = 2 * (-Un-4k-1 * A2k + Un-4k-3 * A2k+1)
+		// Vn-4k-3 = 2 * (-Un-4k-1 * A2k+1 - Un-4k-3 * A2k)
+		
+		// First half mirrored index:
+		// V4k+3 = 2 * (Un-4k-4 * Ar2k - Un-4k-2 * Ar2k+1)
+		// V4k+1 = 2 * (Un-4k-4 * Ar2k+1 + Un-4k-2 * Ar2k)
+		
+		// Endresult:
+		// First half mirrored index mirrored array:
+		// V4k+3 = 2 * (-U4k+3 * Ar2k + U4k+1 * Ar2k+1)
+		// V4k+1 = 2 * (-U4k+3 * Ar2k+1 - U4k+1 * Ar2k)
+
+		// Second half mirrored index:
+		// V4k+3 = 2 * (-U4k+3 * Ar2k + U4k+1 * Ar2k+1)
+		// V4k+1 = 2 * (-U4k+3 * Ar2k+1 - U4k+1 * Ar2k)
+		
+		// Second half mirrored index plus nHalf:
+		// V4k+3+nHalf = 2 * (-U4k+3+nHalf * Ar2k+nHalf + U4k+1+nHalf * Ar2k+1+nHalf)
+		// V4k+1+nHalf = 2 * (-U4k+3+nHalf * Ar2k+1+nHalf - U4k+1+nHalf * Ar2k+nHalf)
+		
+		// Endresult:
+		// Second half mirrored index mirrored array plus nHalf:
+		// V4k+3+nHalf = 2 * (UnHalf-4k-4 * Ar2k+nHalf - UnHalf-4k-2 * Ar2k+1+nHalf)
+		// V4k+1+nHalf = 2 * (UnHalf-4k-4 * Ar2k+1+nHalf + UnHalf-4k-2 * Ar2k+nHalf)
+		
+		// W4k+3+nHalf = V4k+3+nHalf + V4k+3
+		// W4k+1+nHalf = V4k+1+nHalf + V4k+1
+		// W4k+3 = (V4k+3+nHalf - V4k+3) * Ar4k - (V4k+1+nHalf - V4k+1) * Ar4k+1
+		// W4k+1 = (V4k+1+nHalf - V4k+1) * Ar4k - (V4k+3+nHalf - V4k+3) * Ar4k+1
+		
+		for (k = 0; k < nEighth; k++) {
+			i4k = k << 2;
+			i2k = k << 1;
+			i2kPlus1 = i2k | 1;
+			i4kPlus1 = i4k | 1;
+			i4kPlus3 = i4k | 3;
+			i2kPlusNquarter = i2k | nQuarter;
+			i2kPlus1PlusNquarter = i2kPlus1 | nQuarter;
+			iNhalfMinus4kMinus4 = iNhalfMinus4 - i4k;
+			w4kPlus1 = in[i4kPlus1] * floor[i4kPlus1];
+			w4kPlus3 = in[i4kPlus3] * floor[i4kPlus3];
+			wNhalfMinus4kMinus4 = in[iNhalfMinus4kMinus4] * floor[iNhalfMinus4kMinus4];
+			wNhalfMinus4kMinus2 = in[iNhalfMinus4kMinus4 | 2] * floor[iNhalfMinus4kMinus4 | 2];
+			ar2k = AR[i2k];
+			ar2kPlus1 = AR[i2kPlus1];
+			ar2kPlusNhalf = AR[i2kPlusNquarter];
+			ar2kPlus1PlusNhalf = AR[i2kPlus1PlusNquarter];
+			ar4k = AR[i4k];
+			ar4kPlus1 = AR[i4kPlus1];
+			factor1 = -w4kPlus3 * ar2kPlus1 + w4kPlus1 * ar2k; // V4k+3
+			factor2 = -w4kPlus3 * ar2k - w4kPlus1 * ar2kPlus1; // V4k+1
+			factor3 = wNhalfMinus4kMinus4 * ar2kPlus1PlusNhalf - wNhalfMinus4kMinus2 * ar2kPlusNhalf; // V4k+3+nHalf
+			factor4 = wNhalfMinus4kMinus4 * ar2kPlusNhalf + wNhalfMinus4kMinus2 * ar2kPlus1PlusNhalf; // V4k+1+nHalf
+			out[i2kPlus1PlusNquarter] = factor1 + factor3;
+			out[i2kPlusNquarter] = factor2 + factor4;
+			factor5 = factor3 - factor1;
+			factor6 = factor4 - factor2;
+			out[i2kPlus1] = factor5 * ar4kPlus1 - factor6 * ar4k;
+			out[i2k] =      factor5 * ar4k + factor6 * ar4kPlus1;
+		}
+
+		for (l = 0; l < lEnd; l++) {
+			k0 = n >>> l + 2;
+			k1 = 1 << l + 3;
+			k0Half = k0 >>> 1;
+			rEnd = k0 >>> 2;
+			sEnd = k1 >>> 2;
+			for (r = 0; r < rEnd; r++) {
+				iNhalfMinus2Minusr2 = iNhalfMinus2 - (r << 1);
+				ark1 = A[rk1 = r * k1];
+				ark1Plus1 = A[rk1 | 1];
+				for (s = 0; s < sEnd; s++) {
+					downEvenIndex = iNhalfMinus2Minusr2 - k0 * s;
+					downOddIndex = downEvenIndex - k0Half;
+					upEven = out[upEvenIndex = downEvenIndex | 1];
+					upOdd = out[upOddIndex = downOddIndex | 1];
+					downEven = out[downEvenIndex];
+					downOdd = out[downOddIndex];
+					out[upEvenIndex] = upEven + upOdd;
+					out[downEvenIndex] = downEven + downOdd;
+					factor5 = upEven - upOdd;
+					factor6 = downEven - downOdd;
+					out[upOddIndex] =   factor5 * ark1 - factor6 * ark1Plus1;
+					out[downOddIndex] = factor5 * ark1Plus1 + factor6 * ark1;
+				}
+ 			}
+		}
+		
+		// Un-2k-1 = W4k
+		// Un-2k-2 = W4k+1
+		// UnThreeFourths-2k-1 = W4k+2
+		// UnThreeFourths-2k-2 = W4k+3
+
+		// Partial mirrored indices:
+		// Un-2k-1 = W4k
+		// Un-2k-2 = W4k+1
+		// U2k+1+nHalf = WnHalf-4k-2
+		// U2k+nHalf = WnHalf-4k-1
+
+		// Faktor1 = (WnHalf-4k-1 + W4k+1)
+		// Faktor2 = (WnHalf-4k-1 - W4k+1) * C2k+1
+		// Faktor3 = (WnHalf-4k-2 + W4k  ) * C2k
+		// Faktor4 = (WnHalf-4k-2 - W4k  )
+		// Faktor5 = (WnHalf-4k-2 + W4k  ) * C2k+1
+		// Faktor6 = (WnHalf-4k-1 - W4k+1) * C2k
+
+		// V2k+nHalf    =  Faktor1+Faktor2+Faktor3
+		// Vn-2k-2      =  Faktor1-Faktor2-Faktor3
+		// V2k+1+nHalf  =  Faktor4+Faktor5-Faktor6
+		// Vn-2k-1      = -Faktor4+Faktor5-Faktor6
+		
+		for (k = 0; k < nEighth; k++) {
+			i4k = k << 2;
+			i4kr = bitreversedIndex[k] << 2;
+			iNhalfMinus4kMinus4r = iNhalfMinus4 - i4kr;
+			i2k = k << 1;
+			c2k = C[i2k];
+			c2kPlus1 = C[i2k | 1];
+			w4k = out[i4kr];
+			w4kPlus1 = out[i4kr | 1];
+			wNhalfMinus4kMinus1 = out[iNhalfMinus4kMinus4r | 3];
+ 			wNhalfMinus4kMinus2 = out[iNhalfMinus4kMinus4r | 2];
+ 			base1 = wNhalfMinus4kMinus1 - w4kPlus1;
+			base2 = wNhalfMinus4kMinus2 + w4k;
+ 			factor1 =  wNhalfMinus4kMinus1 + w4kPlus1;
+ 			factor2 = base1 * c2kPlus1;
+ 			factor3 = base2 * c2k;
+			factor4 =  wNhalfMinus4kMinus2 - w4k;
+			factor5 = base2 * c2kPlus1;
+ 			factor6 = base1 * c2k;
+			in[i2k]					=  factor1 + factor2 + factor3;
+			in[iNhalfMinus2 - i2k]   =  factor1 - factor2 - factor3;
+			in[i2k | 1]				=  factor4 + factor5 - factor6;
+			in[iNhalfMinus1 - i2k]   = -factor4 + factor5 - factor6;
+		}
+		
+		for (k = 0; k < nQuarter; k++) {
+			i2k = k << 1;
+ 			i2kPlus1 = i2k | 1;
+ 			iNquarterMinuskMinus1 = iNquarterMinus1 - k;
+			iNthreeFourthsMinuskMinus1 = iNthreeFourthsMinus1 - k;
+ 			iNthreeFourthsPlusk = nThreeFourths | k;
+			iNquarterPlusk = nQuarter | k;
+			bh2k = BH[i2k];
+			bh2kPlus1 = BH[i2kPlus1];
+			factor5 = in[i2k];
+			factor6 = in[i2kPlus1];
+			factor1 = factor5 * bh2k + factor6 * bh2kPlus1;
+			factor2 = factor5 * bh2kPlus1 - factor6 * bh2k;
+			out[iNquarterMinuskMinus1] = factor2 * window[iNquarterMinuskMinus1];
+			out[iNthreeFourthsPlusk] = -factor1 * window[iNthreeFourthsPlusk];
+			out[iNquarterPlusk] = -factor2 * window[iNquarterPlusk];
+ 			out[iNthreeFourthsMinuskMinus1] = -factor1 * window[iNthreeFourthsMinuskMinus1];
+		 }
+	}
+
+ 	void close() {
+		A = null;
+		AR = null;
+		BH = null;
+		C = null;
+		bitreversedIndex = null;
+	}
+}

Added: trunk/rhea/com/meviatronic/zeus/castor/Output.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/castor/Output.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/castor/Output.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,170 @@
+/* Castor, a fast Vorbis decoder created by Michael Scheerer.
+ *
+ * Castor decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.castor;
+
+import org.xiph.ogg.*;
+
+import java.io.*;
+
+/**
+ * The <code>Output</code> class implements all output related methods of the decoder.
+ * Furthermore all output channel related settings are performed
+ *
+ * @author    Michael Scheerer
+ */
+abstract public class Output {
+
+  	AudioReader info;
+	int channels;
+	byte[] buffer; // inlining
+	int[] pointer; // inlining
+	
+	private int frameBufferSize;
+	private int frameBufferSizePerChannel;
+	private long granulepos;
+	private long lastGranulepos;
+	private int sampleOffset;
+	private boolean eom;
+	private boolean bom;
+  	
+	Output(AudioReader info){
+	
+		this.info = info;
+		
+		channels = info.channels;
+		
+		frameBufferSizePerChannel = info.blocksizes[1];
+		int frameBufferSize = frameBufferSizePerChannel * channels;
+
+		buffer = new byte[frameBufferSize];
+		pointer = new int[channels];
+	}
+
+	abstract void decode() throws IOException, EndOfMediaException, EndOfPacketException;
+	
+	public final byte[] synthesis(Packet op) throws IOException, EndOfPacketException {
+    	info.loadPacket(op.packetBase, op.packet, op.bytes);
+		
+		eom = op.eos == 1 ? true : false;
+		bom = op.bos == 1 ? true : false;
+
+		resetBufferPointer();
+		
+		decode();
+		
+		if (op.granulepos == -1) {
+			granulepos = lastGranulepos + frameBufferSizePerChannel;
+		} else {
+			granulepos = op.granulepos;
+		}
+		sampleOffset = 0;
+		if (granulepos < 0 && bom) {
+			frameBufferSizePerChannel += granulepos;
+			sampleOffset = (int) -granulepos;
+			if (frameBufferSizePerChannel < 0) {
+				frameBufferSizePerChannel = 0;
+			}
+		}
+		if (granulepos - lastGranulepos < frameBufferSizePerChannel && eom) {
+			frameBufferSizePerChannel = (int) (granulepos - lastGranulepos);
+		}
+		lastGranulepos = granulepos;
+		return buffer;
+	}
+	
+  	public final int getNumberOfSamples() {
+		return frameBufferSizePerChannel;
+  	}
+	
+	public final int getSampleOffset() {
+		return sampleOffset;
+	}
+
+  	/**
+	 * Frees all system resources, which are bounded to this object.
+	 */
+	public void close() {
+		int i;
+		
+		buffer = null;
+		pointer = null;
+	}
+	
+	final void setBlockSize(int bufferSize, int spectrumSize) {
+		frameBufferSizePerChannel = bufferSize << 1;
+		frameBufferSize = frameBufferSizePerChannel * channels;
+	}
+	
+	final void setBuffer(float f, int channelNumber) {
+		
+		if (f >= 1) {
+			f = 1;
+		}
+		if (f <= -1) {
+			f = -1;
+		}
+	
+		f *= 32767;
+
+		short w = (short) f;
+		// one short with little-endian order to 2 bytes in big-endian order!!
+		byte b2 = (byte) (w >>> 8);
+		byte b1 = (byte) w;
+		
+		int p = pointer[channelNumber];
+		
+		buffer[p] = b1;
+		buffer[p + 1] = b2;
+			
+		p += channels << 1;
+		pointer[channelNumber] = p;
+	}
+	
+	private void resetBufferPointer() {
+		for (int i = 0; i < channels; i++) {
+			pointer[i] = 2 * i;
+		}
+	}
+	
+	final boolean bookIsUnused(int bookNumber) {
+		return info.bookIsUnused(bookNumber);
+	}
+	
+	final int get1() throws EndOfPacketException {
+		return info.getLittleEndian1();
+	}
+	
+	final int get(int i) throws EndOfPacketException {
+		return info.getLittleEndian(i);
+	}
+	 
+	final int getCodeWord(int bookNumber) throws IOException, EndOfPacketException {
+		return info.getCodeWord(bookNumber);
+	}
+	
+	final static int ilog(int v) {
+		return AudioReader.ilog(v);
+	}
+}

Added: trunk/rhea/com/meviatronic/zeus/castor/README.txt
===================================================================
--- trunk/rhea/com/meviatronic/zeus/castor/README.txt	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/castor/README.txt	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,94 @@
+	Castor, a fast Vorbis decoder created by Michael Scheerer.
+	Castor decoder (c) 2009 Michael Scheerer www.meviatronic.com
+
+	Many thanks to
+	Monty <monty at xiph.org> and
+	The XIPHOPHORUS Company http://www.xiph.org/ .
+	
+	Castor's IMDCT based on:
+	The use of multirate filter banks for coding of high quality digital audio,
+	6th European Signal Processing Conference (EUSIPCO), Amsterdam, June 1992, Vol.1, pages 211-214Th,
+	Sporer Kh.Brandenburg B.Edler
+	
+	Features:
+ 	- 9 loops and one threefold loop.
+	
+	Features of Castor's enhanced IMDCT:
+	- inplacing inside the performance critical part.
+ 	- 3 loops and one threefold nested loop.
+ 	- includes windowing.
+ 	- includes dot product.
+	- 2 loops plus a windowing loop less than the IMDCT of the current reference decoder.
+	
+	Castor's CRC32 based on (but here used inside the Ogg Framing):
+	public domain code by
+	Ross Williams (ross at guest.adelaide.edu.au).
+	A 32 bit CRC value (direct algorithm, initial val and final XOR = 0, generator polynomial=0x04c11db7) is used.
+	The value is computed over the entire header (with the CRC field in the header set to zero)
+	and then continued over the page. The CRC field is then filled with the computed value.
+
+	Castor's huffman decoding based on:
+ 	Self developed algorithm (deflated binary tree approach -
+	a kind of a 2 pow n compression), therefore there's no reference.
+	Dr. m. m. Timothy B. Terriberry pointed out, that this kind of approach is at least since 1993 a
+	reinvention:
+	R. Hashemian, "High Speed Search and Memory Efficient
+    Huffman Coding," 1993.
+	
+	Castor's bitstream decoding based on:
+ 	Self developed algorithm, therefore there's no reference.
+
+	Summary:
+	
+	Advantages of Castor over the current reference decoder (libVorbis 1.2.3):
+	- in some technical aspects better IMDCT.
+	- drastical reduced binary or bytecode size
+ 	  (from 50 Kbyte Java bytecode ripped of floor 0 and encoder stuff to only 35 Kbyte including Helena).
+ 	- support of VQ lookup type 0 (the spec describes type 0 ambigiously as
+ 	  indirectly allowed and forbidden).
+ 	- support of all specified truncated packet operations.
+ 	- support of codebooks with a single used entry.
+ 	
+ 	Advantages of Castor over an older Java version of the reference decoder:
+	- memory consumption is lower (under Java according to the taskmanager).
+	- performance consumption is lower (under Java according to the taskmanager).
+ 	
+ 	The decoder itself supports full gapless playerback and positive time offset (broadcaststream).
+ 	
+ 	The code size and/or memory consumption may be of interest for
+ 	firmware developers of hardware players.
+ 	
+ 	A firmware port of Castor should replace the recursions during the
+ 	Huffman decoder initialization. Under Java, this recursion based initialization
+ 	is faster than the non recursion version.
+ 	
+ 	Todo:
+ 	
+ 	Exact performance tests against the actual reference decoder.
+ 	
+ 	Because of the small codesize of Castor, the decoder may
+ 	be the right one for e.g. firmware/HDL/ASIC developers.
+ 	
+ 	A C++ version of this decoder should be tested with the huffman decoding
+ 	approach of the reference decoder.
+ 		
+ 	Floor 0 decoding may be implemented, if neccessary.
+ 	According to
+ 	
+	http://www.mp3-tech.org/programmer/docs/embedded_vorbis_thesis.pdf
+	
+	is this floor type not used anymore, due to poor performance and high decoder
+ 	complexity compared to floor 1. Floor 0 was replaced in an early beta, but is still part
+ 	of the standard end hence needs to be supported by a compliant decoder.
+ 	
+ 	Since the current Ogg/Vorbis standard includes features that are not currently used,
+ 	some very unlikely to ever be used (e.g. window lengths of up to 8192 samples), and
+ 	others that are simply outdated (e.g. floor type 0), it is possible to remove support
+ 	for these features from the decoder while still being able to play back almost every
+ 	available Ogg/Vorbis stream. Of course the decoder can no longer be considered fully
+ 	compliant with the standard.
+ 	
+ 	Appreciations:
+ 	
+ 	Very thanks to Dr. m. m. Timothy B. Terriberry for reviewing
+ 	the huffman decoding.

Added: trunk/rhea/com/meviatronic/zeus/castor/VorbisDecoder.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/castor/VorbisDecoder.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/castor/VorbisDecoder.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,1045 @@
+/* Castor, a fast Vorbis decoder created by Michael Scheerer.
+ *
+ * Castor decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.castor;
+
+import java.io.*;
+
+/**
+ * The <code>VorbisDecoder</code> class handles the main decoding of all vorbis formats.
+ *
+ * @author	Michael Scheerer
+ */
+public final class VorbisDecoder extends Output {
+	
+	private final static int FLOOR_MULTIPLIER[] = {
+		256, 128, 86, 64
+	};
+	
+	private final static float FLOOR1_INVERSE_DB_TABLE[] = {
+		1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F,
+		1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F,
+		1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F,
+		2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F,
+		2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F,
+		3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F,
+		4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F,
+		6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F,
+		7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F,
+		1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F,
+		1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F,
+		1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F,
+		2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F,
+		2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F,
+		3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F,
+		4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F,
+		5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F,
+		7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F,
+		9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F,
+		1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F,
+		1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F,
+		2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F,
+		2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F,
+		3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F,
+		4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F,
+		5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F,
+		7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F,
+		9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F,
+		0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F,
+		0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F,
+		0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F,
+		0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F,
+		0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F,
+		0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F,
+		0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F,
+		0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F,
+		0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F,
+		0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F,
+		0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F,
+		0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F,
+		0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F,
+		0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F,
+		0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F,
+		0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F,
+		0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F,
+		0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F,
+		0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F,
+		0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F,
+		0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F,
+		0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F,
+		0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F,
+		0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F,
+		0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F,
+		0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F,
+		0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F,
+		0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F,
+		0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F,
+		0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F,
+		0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F,
+		0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F,
+		0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F,
+		0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F,
+		0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F,
+		0.82788260F, 0.88168307F, 0.9389798F, 1.F
+	};
+	
+	private Imdct[] imdct = {new Imdct(), new Imdct()};
+	private float[][] pcm;
+	private float[][] previousPcm;
+	private float[][] windowTable = new float[5][];
+	private float[] window;
+	private float[] zeroFloats;
+	private int blocksize0, blocksize1, n, previousN;
+	private int modeNumber;
+	private int modeNumberBits;
+	private int vorbisModeBlockflag;
+	private int previousVorbisModeBlockflag;
+	private int vorbisModeMapping;
+	private boolean[] noResidue;
+	private float[][] floor;
+	private float[][] residue;
+	private float[][] residueBundle;
+	private Imdct cimdct;
+	private int[][] lowNeighborOffsetTable;
+	private int[][] highNeighborOffsetTable;
+	private int[][] sortTable;
+	private int[][][] classificationTable;
+	private int[][][] classifications;
+	private int[] floor1Step2Flag;
+	private int[] floor1FinalY;
+	private int[] floor1Y;
+	
+	/**
+	 * Constructs an instance of <code>VorbisDecoder</code> with a
+	 * <code>AudioReader</code> object containing all necessary informations
+	 * about the media source.
+	 *
+	 * @param info     the <code>AudioReader</code> object containing all
+	 *      necessary informations about the media source
+	 */
+	public VorbisDecoder(AudioReader info) {
+		super(info);
+		int i;
+		int floor1MaximumValues = info.floor1MaximumValues;
+		int floor1XListLength = info.floor1XList.length;
+			
+		blocksize0 = info.blocksizes[0];
+		blocksize1 = info.blocksizes[1];
+		modeNumberBits = info.modeNumberBits;
+		floor = new float[channels][blocksize1 >>> 1];
+		residue = new float[channels][blocksize1 >>> 1];
+		residueBundle = new float[channels][];
+		
+		zeroFloats = new float[blocksize1];
+		
+		lowNeighborOffsetTable = new int[floor1XListLength][];
+		highNeighborOffsetTable = new int[floor1XListLength][];
+		sortTable = new int[floor1XListLength][];
+		
+		floor1Step2Flag = new int[floor1MaximumValues];
+		floor1FinalY = new int[floor1MaximumValues];
+		floor1Y = new int[floor1MaximumValues];
+		
+		for (i = 0; i < floor1XListLength; i++) {
+			initializeFloorDecoding(i);
+		}
+		
+		classifications = new int[channels][blocksize1 >>> 1][];
+		initializeClassification();
+		
+		pcm = new float[channels][blocksize1];
+		noResidue = new boolean[channels];
+		previousPcm = new float[channels][blocksize1];
+		
+		windowTable[0] = new float[blocksize0];
+		windowTable[1] = new float[blocksize1];
+		windowTable[2] = new float[blocksize1];
+		windowTable[3] = new float[blocksize1];
+		windowTable[4] = new float[blocksize1];
+		
+		imdct[0].initialize(blocksize0);
+		imdct[1].initialize(blocksize1);
+		
+		initializeWindowing(blocksize0, 0, 0, 0);
+		initializeWindowing(blocksize1, 1, 0, 0);
+		initializeWindowing(blocksize1, 1, 0, 1);
+		initializeWindowing(blocksize1, 1, 1, 0);
+		initializeWindowing(blocksize1, 1, 1, 1);
+	}
+	
+	void decode() throws IOException, EndOfMediaException, EndOfPacketException {
+		int i;
+		
+		if (get1() != 0) {
+			throw new InterruptedIOException("No audio packet");
+		}
+		
+		modeNumber = get(modeNumberBits);
+		vorbisModeBlockflag = info.vorbisModeBlockflag[modeNumber];
+		n = info.blocksizes[vorbisModeBlockflag];
+		previousN = info.blocksizes[previousVorbisModeBlockflag];
+		
+		for (i = 0; i < channels; i++) {
+			noResidue[i] = false;
+			System.arraycopy(zeroFloats, 0, residue[i], 0, n / 2);
+		}
+		
+		cimdct = imdct[vorbisModeBlockflag];
+		
+		setBlockSize(previousN + n >>> 2, n);
+		
+		int previousWindowFlag = 0, nextWindowFlag = 0;
+		
+		int index = 0;
+		
+		if (vorbisModeBlockflag == 1) {
+			previousWindowFlag = get1();
+			nextWindowFlag = get1();
+		}
+		
+		if (previousWindowFlag == 0 && nextWindowFlag == 1) {
+			index = 2;
+		} else if (previousWindowFlag == 1 && nextWindowFlag == 0) {
+			index = 3;
+		} else if (previousWindowFlag == 1 && nextWindowFlag == 1) {
+			index = 4;
+		} else if (vorbisModeBlockflag == 1) {
+			index = 1;
+		}
+	
+		window = windowTable[index];
+		
+		vorbisModeMapping = info.vorbisModeMapping[modeNumber];
+		
+		boolean noResidues = false;
+		
+		try {
+			for (i = 0; i < channels; i++) {
+				decodeFloor(i);
+			}
+		} catch (EndOfPacketException e) {
+			noResidues = true;
+		}
+		if (!noResidues) {
+			nonzeroVectorPropagate();
+			try {
+				if (decodeResidue()) {
+					noResidues = true;
+				}
+			} catch (EndOfPacketException e) {}
+			if (!noResidues) {
+				inverseCoupling();
+			}
+		}
+		if (noResidues) {
+			for (i = 0; i < channels; i++) {
+				float[] p = pcm[i];
+				System.arraycopy(zeroFloats, 0, p, 0, p.length);
+			}
+		} else {
+			for (i = 0; i < channels; i++) {
+				if (noResidue[i]) {
+					float[] p = pcm[i];
+					System.arraycopy(zeroFloats, 0, p, 0, p.length);
+					continue;
+				}
+				imdct(residue[i], pcm[i], window, floor[i]);
+			}
+		}
+		postProcessingPcm();
+	}
+	
+	private void decodeFloor(int channel) throws IOException, EndOfMediaException, EndOfPacketException {
+		int i, j;
+		int submapNumber = info.vorbisMappingMux[vorbisModeMapping][channel];
+		int floorNumber = info.vorbisMappingSubmapFloor[vorbisModeMapping][submapNumber];
+			
+		if (get1() == 0) {
+			noResidue[channel] = true;
+			return;
+		}
+			
+		int floor1Multiplier = info.floor1Multiplieres[floorNumber];
+		int range = FLOOR_MULTIPLIER[floor1Multiplier - 1];
+			
+		int[] floor1XList = info.floor1XList[floorNumber];
+		
+		int floor1Values = floor1XList.length;
+		
+		floor1Y[0] = get(ilog(range - 1));
+		floor1Y[1] = get(ilog(range - 1));
+			
+		int offset = 2;
+		int[] floor1PartitionClass = info.floor1PartitionClassList[floorNumber];
+		int floor1Partitions = floor1PartitionClass.length;
+		int[] floor1ClassDimensions = info.floor1ClassDimensions[floorNumber];
+		int[] floor1ClassMasterbooks = info.floor1ClassMasterbooks[floorNumber];
+		int[] floor1ClassSubclasses = info.floor1ClassSubclasses[floorNumber];
+		int[][] floor1SubclassBooks = info.floor1SubclassBooks[floorNumber];
+			
+		int pclass;
+		int cdim;
+		int cbits;
+		int csub;
+		int cval;
+		int book;
+		int cdimPlusOffset;
+			
+		for (i = 0; i < floor1Partitions; i++) {
+			pclass = floor1PartitionClass[i];
+			cdim  = floor1ClassDimensions[pclass];
+			cdimPlusOffset = cdim + offset;
+			cbits = floor1ClassSubclasses[pclass];
+			csub = (1 << cbits) - 1;
+			cval = 0;
+			if (cbits > 0) {
+				cval = getCodeWord(floor1ClassMasterbooks[pclass]);
+			}
+			for (j = offset; j < cdimPlusOffset; j++) {
+				book = floor1SubclassBooks[pclass][cval & csub];
+				cval >>>= cbits;
+				if (book >= 0) {
+					floor1Y[j] = getCodeWord(book);
+				} else {
+					floor1Y[j] = 0;
+				}
+			}
+			offset += cdim;
+		}
+		
+		floor1Step2Flag[0] = 1;
+		floor1Step2Flag[1] = 1;
+		floor1FinalY[0] = floor1Y[0];
+		floor1FinalY[1] = floor1Y[1];
+			
+		int lowNeighborOffset;
+		int highNeighborOffset;
+		int predicted;
+		int val;
+		int highroom;
+		int lowroom;
+		int room;
+			
+		int[] low = lowNeighborOffsetTable[floorNumber];
+		int[] high = highNeighborOffsetTable[floorNumber];
+		int[] sort = sortTable[floorNumber];
+
+		for (i = 2; i < floor1Values; i++) {
+			lowNeighborOffset = low[i];
+			highNeighborOffset = high[i];
+			predicted = renderPoint(floor1XList[lowNeighborOffset],
+									floor1FinalY[lowNeighborOffset],
+									floor1XList[highNeighborOffset],
+									floor1FinalY[highNeighborOffset],
+									floor1XList[i]);
+			
+			val = floor1Y[i];
+			highroom = range - predicted;
+			lowroom = predicted;
+				
+			room = (highroom < lowroom ? highroom : lowroom) << 1;
+
+			if (val != 0) {
+				floor1Step2Flag[lowNeighborOffset] = 1;
+				floor1Step2Flag[highNeighborOffset] = 1;
+				floor1Step2Flag[i] = 1;
+				if (val >= room) {
+					if (highroom > lowroom) {
+						floor1FinalY[i] = val - lowroom + predicted;
+					} else {
+						floor1FinalY[i] = predicted - val + highroom - 1;
+					}
+				} else {
+					if ((val & 0x1) == 1) {
+						floor1FinalY[i] = predicted - ((val + 1) >>> 1);
+					} else {
+						floor1FinalY[i] = predicted + (val >>> 1);
+					}
+				}
+			} else {
+				floor1Step2Flag[i] = 0;
+				floor1FinalY[i] = predicted;
+			}
+		}
+			
+		float[] flro = floor[channel];
+		int hx = 0;
+		int hy = 0;
+		int lx = 0;
+		int ly = floor1FinalY[0] * floor1Multiplier;
+		int actualSize = n / 2;
+
+		for (i = 1; i < floor1Values; i++) {
+			j = sort[i];
+			if (floor1Step2Flag[j] == 1) {
+				hy = floor1FinalY[j] * floor1Multiplier;
+				hx = floor1XList[j];
+				renderLine(lx, ly, hx, hy, flro);
+				lx = hx;
+				ly = hy;
+			}
+		}
+		if (hx < actualSize) {
+			renderLine(hx, hy, actualSize, hy, flro);
+		}
+	}
+	
+	private void nonzeroVectorPropagate() {
+		int[] magnitude = info.vorbisMappingMagnitude[vorbisModeMapping];
+		int[] angle = info.vorbisMappingAngle[vorbisModeMapping];
+		int m;
+		int a;
+		int i;
+		
+		for (i = 0; i < magnitude.length; i++) {
+			m = magnitude[i];
+			a = angle[i];
+			if (!noResidue[m] || !noResidue[a]) {
+				noResidue[m] = false;
+				noResidue[a] = false;
+			}
+		}
+	}
+
+	private boolean decodeResidue() throws IOException, EndOfMediaException, EndOfPacketException {
+		int i, j;
+		int[] vorbisMappingSubmapResidue = info.vorbisMappingSubmapResidue[vorbisModeMapping];
+		int[] vorbisMappingMux = info.vorbisMappingMux[vorbisModeMapping];
+		int ch;
+		int dch, dch2;
+		boolean doNotDecode;
+		int residueNumber;
+		int residueType;
+
+		for (i = 0; i < vorbisMappingSubmapResidue.length; i++) {
+			ch = dch = dch2 = 0;
+			residueNumber = vorbisMappingSubmapResidue[i];
+			residueType = info.vorbisResidueTypes[residueNumber];
+			
+			for (j = 0; j < channels; j++) {
+				if (vorbisMappingMux[j] == i) {
+					if (!(doNotDecode = noResidue[j]) || residueType == 2) {
+						residueBundle[dch++] = residue[j];
+						if (!doNotDecode) {
+							dch2++;
+						}
+					}
+					ch++;
+				}
+			}
+			if (dch2 == 0) {
+				return false;
+			}
+			if (decodeVectors(dch, residueNumber, residueType)) {
+				continue;
+			}
+		}
+		return false;
+	}
+				
+	private boolean decodeVectors(int dch, int residueNumber, int residueType) throws IOException, EndOfMediaException, EndOfPacketException {
+		int i, j, k, l, pass, entryTemp, end;
+		int residueBegin = info.residueBegin[residueNumber];
+		int residueEnd = info.residueEnd[residueNumber];
+		int residuePartitionSize = info.residuePartitionSize[residueNumber];
+		int residueClassifications = info.residueClassifications[residueNumber];
+		int residueClassbook = info.residueClassbooks[residueNumber];
+		int maximumPasses = info.residueMaximumPasses[residueNumber];
+		int[] residueCascade = info.residueCascade[residueNumber];
+		int[][] residueBooks = info.residueBooks[residueNumber];
+		int actualSize = n / 2;
+		int vectors = dch;
+
+		if (residueType == 2) {
+			actualSize *= dch;
+		}
+		
+		int limitResidueBegin = residueBegin < actualSize ? residueBegin : actualSize;
+		int limitResidueEnd = residueEnd < actualSize ? residueEnd : actualSize;
+		int codebookDimensions[] = info.codebookDimensions;
+		int codebookDimension;
+		int classwordsPerCodeword = codebookDimensions[residueClassbook];
+		float[][] vqLookupTable = info.valueVector;
+		float[] vqLookup;
+		float[] out;
+
+		int nToRead = limitResidueEnd - limitResidueBegin;
+		int partitionsToRead = nToRead / residuePartitionSize;
+		
+		if (nToRead == 0) {
+			return true;
+		}
+
+		int partitionCount;
+		int codewordCount;
+		int temp;
+		int vqclass;
+		int vqbook;
+		
+		int[][] classificationTablePerResidue = classificationTable[residueNumber];
+		
+		for (pass = 0; pass < maximumPasses; pass++) {
+			partitionCount = 0;
+			codewordCount = 0;
+			
+			if (residueType == 0) {
+				while (partitionCount < partitionsToRead) {
+					if (pass == 0) {
+						for (j = 0; j < vectors; j++) {
+							temp = getCodeWord(residueClassbook);
+							classifications[j][codewordCount] = classificationTablePerResidue[temp];
+						}
+					}
+					for (i = 0; i < classwordsPerCodeword && partitionCount < partitionsToRead; i++) {
+						k = end = limitResidueBegin + partitionCount * residuePartitionSize;
+						for (j = 0; j < vectors; j++) {
+							vqclass = classifications[j][codewordCount][i];
+							out = residueBundle[j];
+							if ((residueCascade[vqclass] & 1 << pass) != 0) {
+								vqbook = residueBooks[vqclass][pass];
+								vqLookup = vqLookupTable[vqbook];
+							
+								codebookDimension = codebookDimensions[vqbook];
+								if(bookIsUnused(vqbook)) {
+									continue;
+								}
+								int step = residuePartitionSize / codebookDimension;
+								end += step;
+
+								for (; k < end; k++) {
+									entryTemp = getCodeWord(vqbook) * codebookDimension;
+									for (l = 0; l < codebookDimension; l++) {
+										out[k + l * step] += vqLookup[entryTemp + l];
+									}
+								}
+							}
+						}
+						partitionCount++;
+					}
+					codewordCount++;
+				}
+			} else if (residueType == 1) {
+				while (partitionCount < partitionsToRead) {
+					if (pass == 0) {
+						for (j = 0; j < vectors; j++) {
+							temp = getCodeWord(residueClassbook);
+							classifications[j][codewordCount] = classificationTablePerResidue[temp];
+						}
+					}
+					for (i = 0; i < classwordsPerCodeword && partitionCount < partitionsToRead; i++) {
+						k = end = limitResidueBegin + partitionCount * residuePartitionSize;
+							
+						for (j = 0; j < vectors; j++) {
+							vqclass = classifications[j][codewordCount][i];
+							out = residueBundle[j];
+							if ((residueCascade[vqclass] & 1 << pass) != 0) {
+								vqbook = residueBooks[vqclass][pass];
+								vqLookup = vqLookupTable[vqbook];
+							
+								codebookDimension = codebookDimensions[vqbook];
+								if(bookIsUnused(vqbook)) {
+									continue;
+								}
+								end += residuePartitionSize;
+
+								do {
+									entryTemp = getCodeWord(vqbook) * codebookDimension;
+									for (l = 0; l < codebookDimension; l++, k++) {
+										out[k] += vqLookup[entryTemp + l];
+									}
+								} while (k < end);
+							}
+						}
+						partitionCount++;
+					}
+					codewordCount++;
+				}
+			} else {
+				while (partitionCount < partitionsToRead) {
+					if (pass == 0) {
+						temp = getCodeWord(residueClassbook);
+						classifications[0][codewordCount] = classificationTablePerResidue[temp];
+					}
+					for (i = 0; i < classwordsPerCodeword && partitionCount < partitionsToRead; i++) {
+						k = end = limitResidueBegin + partitionCount * residuePartitionSize;
+						vqclass = classifications[0][codewordCount][i];
+						if ((residueCascade[vqclass] & 1 << pass) != 0) {
+							vqbook = residueBooks[vqclass][pass];
+							vqLookup = vqLookupTable[vqbook];
+							
+							codebookDimension = codebookDimensions[vqbook];
+							if(bookIsUnused(vqbook)) {
+								continue;
+							}
+							end += residuePartitionSize;
+							
+							if (codebookDimension == 2) {
+								do {
+									entryTemp = getCodeWord(vqbook) * codebookDimension;
+									residueBundle[k % dch][k / dch] += vqLookup[entryTemp];
+									k++;
+									residueBundle[k % dch][k / dch] += vqLookup[entryTemp + 1];
+									k++;
+								} while (k < end);
+							} else if (codebookDimension == 4) {
+								do {
+									entryTemp = getCodeWord(vqbook) * codebookDimension;
+									residueBundle[k % dch][k / dch] += vqLookup[entryTemp];
+									k++;
+									residueBundle[k % dch][k / dch] += vqLookup[entryTemp + 1];
+									k++;
+									residueBundle[k % dch][k / dch] += vqLookup[entryTemp + 2];
+									k++;
+									residueBundle[k % dch][k / dch] += vqLookup[entryTemp + 3];
+									k++;
+								} while (k < end);
+							} else {
+								do {
+									entryTemp = getCodeWord(vqbook) * codebookDimension;
+									for (l = 0; l < codebookDimension; l++, k++) {
+										residueBundle[k % dch][k / dch] += vqLookup[entryTemp + l];
+									}
+								} while (k < end);
+							}
+						}
+						partitionCount++;
+					}
+					codewordCount++;
+				}
+			}
+		}
+		return false;
+	}
+
+	private void inverseCoupling() {
+		int[] magnitude = info.vorbisMappingMagnitude[vorbisModeMapping];
+		int[] angle = info.vorbisMappingAngle[vorbisModeMapping];
+		float[] magnitudeVector;
+		float[] angleVector;
+		float m, a, newM, newA;
+		
+		for (int i = magnitude.length - 1; i >= 0; i--) {
+			magnitudeVector = residue[magnitude[i]];
+			angleVector = residue[angle[i]];
+			
+			for (int j = 0; j < magnitudeVector.length; j++) {
+				m = magnitudeVector[j];
+				a = angleVector[j];
+				if (m > 0) {
+					if (a > 0) {
+						newM = m;
+						newA = m - a;
+					} else {
+						newA = m;
+						newM = m + a;
+					}
+				} else {
+					if (a > 0) {
+						newM = m;
+						newA = m + a;
+					} else {
+						newA = m;
+						newM = m - a;
+					}
+				}
+				magnitudeVector[j] = newM;
+				angleVector[j] = newA;
+			}
+		}
+	}
+	
+	private int lowNeighbor(int[] v, int x) {
+		int nMax = 0;
+		int treshold = -1;
+		int vn, vx;
+		
+		for (int n = x - 1; n >= 0; n--) {
+			vn = v[n];
+			vx = v[x];
+			
+			if (vn > treshold && vn < vx) {
+				treshold = vn;
+				nMax = n;
+			}
+		}
+		return nMax;
+	}
+	
+	private int highNeighbor(int[] v, int x) {
+		int nMin = 0;
+		int treshold = Integer.MAX_VALUE;
+		int vn, vx;
+		
+		for (int n = 0; n < x; n++) {
+			vn = v[n];
+			vx = v[x];
+			
+			if (vn < treshold && vn > vx) {
+				treshold = vn;
+				nMin = n;
+			}
+		}
+		return nMin;
+	}
+	
+	private static int renderPoint(int x0, int y0, int x1, int y1, int x) {
+		int dy = y1 - y0;
+		int adx = x1 - x0;
+		int ady = dy;
+		
+		if (ady < 0) {
+			ady = -ady;
+		}
+		
+		int err = ady * (x - x0);
+		int off = err / adx;
+		
+		if (dy < 0) {
+			return y0 - off;
+		}
+		return y0 + off;
+	}
+	
+	private void renderLine(int x0, int y0, int x1, int y1, float[] v) {
+		int dy = y1 - y0;
+		int adx = x1 - x0;
+		int ady = dy;
+		
+		if (ady < 0) {
+			ady = -ady;
+		}
+		
+		int x = x0;
+		int y = y0;
+		int err = -adx;
+		int sy = dy < 0 ? - 1 : + 1;
+		int base = dy / adx;
+		
+		v[x] = FLOOR1_INVERSE_DB_TABLE[y];
+			
+		if (base == 0) {
+			
+			if (ady << 1 <= adx) {
+				int x1MinusOne = x1 - 1;
+				int adyMinusAdx = ady - adx;
+					
+				while (++x < x1MinusOne) {
+					err += ady;
+			
+					if (err >= 0) {
+						err += adyMinusAdx;
+						y += sy;
+						v[x++] = FLOOR1_INVERSE_DB_TABLE[y];
+					}
+				
+					v[x] = FLOOR1_INVERSE_DB_TABLE[y];
+				}
+				if (x < x1) {
+					if (err + ady >= 0) {
+						y += sy;
+					}
+					v[x] = FLOOR1_INVERSE_DB_TABLE[y];
+				}
+			} else {
+				while (++x < x1) {
+					err += ady;
+			
+					if (err >= 0) {
+						err -= adx;
+						y += sy;
+					}
+				
+					v[x] = FLOOR1_INVERSE_DB_TABLE[y];
+				}
+			}
+		 } else {
+			int abase = base;
+		
+			if (abase < 0) {
+				abase = -abase;
+			}
+
+			ady -= abase * adx;
+			
+			while (++x < x1) {
+				err += ady;
+			
+				if (err >= 0) {
+					err -= adx;
+					y += sy;
+				}
+				
+				y += base;
+				
+				v[x] = FLOOR1_INVERSE_DB_TABLE[y];
+			}
+		}
+	}
+
+	private void imdct(float[] in, float[] out, float[] window, float[] floor) {
+		cimdct.decode(in, out, window, floor);
+	}
+
+	private void postProcessingPcm() {
+		int i = 0;
+		int j, k = 0;
+		int nHalf = n >>> 1;
+		int previousNhalf = previousN >>> 1;
+		int begin = 0;
+		int middle = nHalf + previousNhalf >>> 1;
+		int end = middle;
+		int kOffset = 0;
+		float f;
+		short w;
+		byte b2;
+		byte b1;
+		int p;
+		
+		if (previousVorbisModeBlockflag == 1 && vorbisModeBlockflag == 0) {
+			begin = previousNhalf - nHalf >>> 1;
+		} else if (previousVorbisModeBlockflag == 0 && vorbisModeBlockflag == 1) {
+			middle = previousNhalf;
+			kOffset = nHalf - previousNhalf >>> 1;
+		}
+		for (; i < begin; i++) {
+			for (j = 0; j < channels; j++) {
+				setBuffer(previousPcm[j][i], j);
+			}
+		}
+		for (; i < middle; i++, k++) {
+			for (j = 0; j < channels; j++) {
+				setBuffer(previousPcm[j][i] + pcm[j][kOffset + k], j);
+			}
+		}
+		for (; i < end; i++, k++) {
+			for (j = 0; j < channels; j++) {
+				setBuffer(pcm[j][kOffset + k], j);
+			}
+		}
+		for (j = 0; j < channels; j++) {
+			System.arraycopy(pcm[j], nHalf, previousPcm[j], 0, nHalf);
+		}
+		previousVorbisModeBlockflag = vorbisModeBlockflag;
+	}
+
+	private void initializeWindowing(int n, int vorbisModeBlockflag, int previousWindowFlag, int nextWindowFlag) {
+		int index = 0;
+		int windowCenter = n / 2;
+		int rightWindowStart, rightWindowEnd, leftWindowStart, leftWindowEnd, leftN, rightN;
+		
+		if (vorbisModeBlockflag == 1 && previousWindowFlag == 0) {
+			leftN = blocksize0 / 2;
+			leftWindowStart = n / 4 - leftN / 2;
+			leftWindowEnd = n / 4 + leftN / 2;
+		} else {
+			leftWindowStart = 0;
+			leftN = leftWindowEnd = windowCenter;
+		}
+			
+		if (vorbisModeBlockflag == 1 && nextWindowFlag == 0) {
+			rightN = blocksize0 / 2;
+			rightWindowStart = n * 3 / 4 - rightN / 2;
+			rightWindowEnd = n * 3 / 4 + rightN / 2;
+		} else {
+			rightN = rightWindowStart = windowCenter;
+			rightWindowEnd = n;
+		}
+		
+		if (previousWindowFlag == 0 && nextWindowFlag == 1) {
+			index = 2;
+		} else if (previousWindowFlag == 1 && nextWindowFlag == 0) {
+			index = 3;
+		} else if (previousWindowFlag == 1 && nextWindowFlag == 1) {
+			index = 4;
+		} else if (vorbisModeBlockflag == 1) {
+			index = 1;
+		}
+
+		int i = leftWindowStart;
+		
+		float[] windowTablePointer = windowTable[index];
+
+		for (; i < leftWindowEnd; i++) {
+			windowTablePointer[i] = (float) Math.sin(0.5 * Math.PI * Math.pow(Math.sin((i - leftWindowStart + 0.5) / leftN * 0.5 * Math.PI), 2));
+		}
+		for (; i < rightWindowStart; i++) {
+			windowTablePointer[i] = 1;
+		}
+		for (; i < rightWindowEnd; i++) {
+			windowTablePointer[i] = (float) Math.sin(0.5 * Math.PI * Math.pow(Math.sin((rightN + i - rightWindowStart + 0.5) / rightN * 0.5 * Math.PI), 2));
+		}
+	}
+	
+	private void initializeFloorDecoding(int floorNumber) {
+		int i, j;
+		int[] floor1XList = info.floor1XList[floorNumber];
+		int floor1Values = floor1XList.length;
+		
+		int[] low = lowNeighborOffsetTable[floorNumber] = new int[floor1Values];
+		int[] high = highNeighborOffsetTable[floorNumber] = new int[floor1Values];
+		int[] sort = sortTable[floorNumber] = new int[floor1Values];
+		int buffer;
+
+		for (i = 1; i < floor1Values; i++) {
+			sort[i] = i;
+		}
+		for (i = 1; i < floor1Values; i++) {
+			for (j = i + 1; j < floor1Values && i < floor1Values - 1; j++) {
+				if (floor1XList[sort[i]] > floor1XList[sort[j]]) {
+					buffer = sort[i];
+					sort[i] = sort[j];
+					sort[j] = buffer;
+				}
+			}
+			low[i] = lowNeighbor(floor1XList, i);
+			high[i] = highNeighbor(floor1XList, i);
+		}
+	}
+	
+	private void initializeClassification() {
+		int i, j, temp;
+
+		classificationTable = new int[info.residueClassifications.length][][];
+		int[][] classificationTableOuterPointer;
+		int[] classificationTableInnerPointer;
+
+		for (i = 0; i < info.residueClassifications.length; i++) {
+			int residueClassifications = info.residueClassifications[i];
+			int residueClassbooks = info.residueClassbooks[i];
+			int classwordsPerCodeword = info.codebookDimensions[residueClassbooks];
+			int maxNumber = (int) Math.pow(residueClassifications, classwordsPerCodeword);
+			int workingDigit = 0;
+			int tempBuffer;
+			int classification;
+			classificationTableOuterPointer = classificationTable[i] = new int[maxNumber][];
+			
+			for(temp = 0; temp < maxNumber; temp++) {
+				classificationTableInnerPointer = classificationTableOuterPointer[temp] = new int[classwordsPerCodeword];
+      			tempBuffer = temp;
+      			workingDigit = maxNumber / residueClassifications;
+				
+      			for(j = 0; j < classwordsPerCodeword; j++){
+					classification = tempBuffer / workingDigit;
+					tempBuffer -= classification * workingDigit;
+					workingDigit /= residueClassifications;
+					classificationTableInnerPointer[j] = classification;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Frees all system resources, which are bounded to this object.
+	 */
+	public void close() {
+		super.close();
+		int i, j;
+		
+		if (pcm != null) {
+			for (i = 0; i < pcm.length; i++) {
+				pcm[i] = null;
+			}
+		}
+		pcm = null;
+		if (previousPcm != null) {
+			for (i = 0; i < previousPcm.length; i++) {
+				previousPcm[i] = null;
+			}
+		}
+		previousPcm = null;
+		
+		if (windowTable != null) {
+			for (i = 0; i < windowTable.length; i++) {
+				windowTable[i] = null;
+			}
+		}
+		windowTable = null;
+		
+		int[][] classificationTablePointer;
+		
+		if (classificationTable != null) {
+			for (i = 0; i < classificationTable.length; i++) {
+				classificationTablePointer = classificationTable[i];
+				for (j = 0; j < classificationTablePointer.length; j++) {
+					classificationTablePointer[j] = null;
+				}
+				classificationTablePointer = null;
+			}
+		}
+		classificationTable = null;
+		if (classifications != null) {
+			for (i = 0; i < classifications.length; i++) {
+				classifications[i] = null;
+			}
+		}
+		classifications = null;
+		if (floor != null) {
+			for (i = 0; i < floor.length; i++) {
+				floor[i] = null;
+			}
+		}
+		floor = null;
+		residueBundle = null;
+		
+		if (residue != null) {
+			for (i = 0; i < residue.length; i++) {
+				residue[i] = null;
+			}
+		}
+		residue = null;
+		
+		if (lowNeighborOffsetTable != null) {
+			for (i = 0; i < lowNeighborOffsetTable.length; i++) {
+				lowNeighborOffsetTable[i] = null;
+			}
+		}
+		lowNeighborOffsetTable = null;
+		
+		if (highNeighborOffsetTable != null) {
+			for (i = 0; i < highNeighborOffsetTable.length; i++) {
+				highNeighborOffsetTable[i] = null;
+			}
+		}
+		highNeighborOffsetTable = null;
+
+		if (sortTable != null) {
+			for (i = 0; i < sortTable.length; i++) {
+				sortTable[i] = null;
+			}
+		}
+		sortTable = null;
+		floor1Step2Flag = null;
+		floor1FinalY = null;
+		floor1Y = null;
+		noResidue = null;
+		zeroFloats = null;
+		if (imdct != null) {
+			imdct[0].close();
+			imdct[1].close();
+			imdct[0] = null;
+			imdct[1] = null;
+		}
+		imdct = null;
+	}
+}

Added: trunk/rhea/com/meviatronic/zeus/helen/BaseTag.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/helen/BaseTag.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/helen/BaseTag.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,53 @@
+/* Helena, a Comment decoder created by Michael Scheerer.
+ *
+ * Helena decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.helen;
+
+import java.util.*;
+
+/**
+ * The <code>BaseTagContent</code> class contains the cloned information related to an Ogg Tag and
+ * is designed to be as flexible as possible to
+ * reduce the number of cases where information has to be returned as binary
+ * when it is rather more structured. <p>
+ *
+ * It provides storage for - a type (e.g. a MIME-type or a language, Text) - a
+ * subtype (text or binary) - a description (text) - the content (text or
+ * binary).
+ *
+ * @author    Michael Scheerer
+ */
+public final class BaseTag extends Hashtable {
+		
+	/**
+	 * Returns a <code>Hashtable</code> representation of this <code>Information</code> object.
+	 *
+	 * @return     a <code>Hashtable</code> representation of this <code>Information</code> object
+	 */
+	public Hashtable getHashtable() {
+		return (Hashtable) this.clone();
+	}
+}
+
+

Added: trunk/rhea/com/meviatronic/zeus/helen/Converter.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/helen/Converter.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/helen/Converter.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,77 @@
+/* Helena, a Comment decoder created by Michael Scheerer.
+ *
+ * Helena decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.helen;
+
+import java.io.*;
+
+/**
+ * The <code>Converter</code> class can be used to transform UTF-8 data to characters.
+ *
+ * @author	Michael Scheerer
+ */
+final class Converter {
+
+    String convert(byte b[]) {
+    	return convert(b, 0, b.length);
+    }
+    
+    String convert(byte b[], int i, int j) {
+		int charIndex = 0, k, l, m, n;
+		
+		char onec = 0;
+		
+		StringBuffer buffer = new StringBuffer();
+		
+		for (int byteIndex = i; byteIndex < j;) {
+        	
+            byte oneb = b[byteIndex++];
+            
+            if (oneb >= 0) {
+				onec = (char) oneb;
+			} else {
+				k = oneb & 0xFF;
+				
+				if ((k >>> 5 & 0x7) == 6 && byteIndex < j) {
+					l = b[byteIndex++];
+					onec = (char)(k << 6 & 0x1F | l & 0x3F);
+				} else if ((k >>> 4 & 0xF) == 14 && byteIndex < j - 1) {
+					l = b[byteIndex++];
+					m = b[byteIndex++];
+					onec = (char)(k << 12 & 0xF | l << 6 & 0x3F | m & 0x3F);
+				} else if (byteIndex < j - 2) {
+					l = b[byteIndex++];
+					m = b[byteIndex++];
+					n = b[byteIndex++];
+					onec = (char)(k << 18 & 0x7 | l << 12 & 0x3F | m << 6 & 0x3F | n & 0x3F);
+				} else {
+					onec = ' ';
+				}
+			}
+			buffer.append(onec);
+		}
+		return buffer.toString();
+    }
+}
+

Added: trunk/rhea/com/meviatronic/zeus/helen/OggTag.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/helen/OggTag.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/helen/OggTag.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,336 @@
+/* Helena, a Comment decoder created by Michael Scheerer.
+ *
+ * Helena decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.helen;
+
+import java.io.*;
+import java.util.*;
+
+import com.meviatronic.zeus.castor.*;
+import com.meviatronic.zeus.pollux.*;
+
+/**
+ * The <code>OggTag</code> class is the main class of this Ogg Comment system.
+ * <p>
+ * Note that this OggTag system requires an OggTag tag
+ * starting at the first byte of the inputstream,
+ * although the OggTag specification doesn't demand this.
+ *
+ * @author    Michael Scheerer
+ */
+public final class OggTag extends Tag {
+
+	/**
+	 * String frameContent keys
+	 */
+	public final static String
+		S_LOCATION = "String location", S_CONTACT = "String contact", S_DESCRIPTION = "String description", S_ORGANIZATION = "String organization",
+		S_VERSION = "String version", S_VENDOR = "String vendor", S_LICENSE = "String license", S_DIRECTOR = "String director", S_PRODUCER = "String producer", S_ACTOR = "String actor",
+		S_TAG = "String tag";
+	
+	private boolean framingBit;
+	private Hashtable frames;
+	private byte[] data;
+	private String vendorString;
+	private int i, j;
+	private int userCommentListLength;
+	private Converter con = new Converter();
+	private byte[] b;
+	private AudioReader reader;
+
+	/**
+	 * Provides access to Ogg tag.
+	 *
+	 * @param reader            AudioReader to read from
+	 * @param framingBit        if an framing bit occurs
+	 * @exception IOException   if an I/O errors occur
+	 */
+	public OggTag(AudioReader reader, boolean framingBit) throws IOException {
+		super();
+		this.framingBit = framingBit;
+		this.reader = reader;
+	}
+	
+	private void buildKeyMapTable() {
+		//text frameContent
+		put(S_ARTIST, "ARTIST");
+		put(S_ALBUM, "ALBUM");
+		put(S_ENCODER, "ENCODER");
+		put(S_TRACK, "TRACKNUMBER");
+		put(S_YEAR, "YEAR");
+		put(S_LOCATION, "LOCATION");
+		put(S_PERFORMER, "PERFORMER");
+		put(S_COPYRIGHT, "COPYRIGHT");
+		put(S_LICENSE, "LICENSE");
+		put(S_DATE, "DATE");
+		put(S_GENRE, "GENRE");
+		put(S_TITLE, "TITLE");
+		put(S_ISRC, "ISRC");
+		put(S_VERSION, "VERSION");
+		put(S_ORGANIZATION, "ORGANIZATION");
+		put(S_CONTACT, "CONTACT");
+		put(S_DESCRIPTION, "DESCRIPTION");
+	}
+
+	/**
+	 * Returns the value to which the specified key is mapped in this hashtable.
+	 * The values are either control flags or informations stored in the tag.
+	 *
+	 * @param key                       the hashtable key
+	 * @return                          the value to which the key is mapped in
+	 *      this hashtable; null if the key is not mapped to any value in this
+	 *      hashtable
+	 */
+	public Object get(Object key) {
+		Object ob = super.get(key);
+
+		if (key.equals(S_TAG_FORMAT) || key.equals(B_TAG) || key.equals(S_VENDOR)) {
+			return ob;
+		}
+		return frames.get(ob);
+	}
+	
+	/**
+	 * Obtains a String describing all information keys and values. With the hashkey
+	 * of a specific information it is possible to obtain the information value.
+	 *
+	 * @return     a String representation all informations
+	 */
+	public String toString() {
+		StringBuffer buff = new StringBuffer();
+		int counter = 0, counter1 = 0;
+		Object key;
+		Object value;
+		Enumeration ekeys1 = keys();
+		if (!ekeys1.hasMoreElements()) {
+			buff.append("{}");
+			return buff.toString();
+		}
+		for (key = ekeys1.nextElement(); ekeys1.hasMoreElements(); key = ekeys1.nextElement()) {
+			value = get(key);
+			if (value != null && !key.equals(S_VENDOR)) {
+				counter++;
+			}
+		}
+		Enumeration ekeys = keys();
+		buff.append("{");
+		buff.append(S_VENDOR + "=");
+		if (counter == 0) {
+			buff.append(get(S_VENDOR));
+		} else {
+			buff.append(get(S_VENDOR) + ", ");
+		}
+		for (key = ekeys.nextElement(); ekeys.hasMoreElements(); key = ekeys.nextElement()) {
+			value = get(key);
+			if (value != null && !key.equals(S_VENDOR)) {
+				buff.append(key + "=");
+				buff.append(value);
+				counter1++;
+				if (counter1 < counter) {
+					buff.append(", ");
+				}
+			}
+		}
+		buff.append("}");
+		return buff.toString();
+	}
+	
+    /**
+     * Creates a shallow copy of this hashtable. The keys and values
+     * themselves are cloned.
+     * This is a relatively expensive operation.
+	 *
+	 * @return     a clone of this instance
+	 */
+	public Object clone() {
+		BaseTag hash = new BaseTag();
+		
+		int i = size();
+		
+		if (i == 0) {
+			return hash;
+		}
+
+		Enumeration ekeys = keys();
+		Enumeration evalues = elements();
+		Object key, value;
+		for (int j = 0; j < i; j++) {
+			key = ekeys.nextElement();
+			value = get(key);
+			if (value != null) {
+				hash.put(key, value);
+			}
+		}
+		return hash;
+	}
+	
+	/*
+	 * Decodes the comment header packet
+	 * @exception IOException           if an I/O errors occur
+	 * @exception EndOfPacketExeption   if an end of packet occur
+	 */
+	public void decode() throws IOException, EndOfPacketException {
+		try {
+			readHeader(reader);
+			buildKeyMapTable();
+			put(S_VENDOR, new String(vendorString));
+			loadFrames(reader, framingBit);
+		} catch (TagException e) {
+			throw new IOException("Tag error");
+		}
+	}
+
+	/**
+	 * Frees all system resources, which are bounded to this object.
+	 */
+	public void close() {
+		con = null;
+		data = null;
+		b = null;
+		vendorString = null;
+		
+		if (frames != null) {
+			frames.clear();
+		}
+		frames = null;
+		super.close();
+	}
+	 
+	private void readHeader(AudioReader reader) throws TagException, IOException, EndOfPacketException {
+		int vendorLength = getInt();
+		
+		if(vendorLength < 0) {
+			throw new TagException("Negative String Size");
+		}
+
+		data = new byte[vendorLength];
+		
+		for (int i = 0; i < vendorLength; i++) {
+			data[i] = (byte) getByte();
+		}
+
+		vendorString = new String(data);
+		
+		userCommentListLength = getInt();
+		
+		if(userCommentListLength < 0) {
+			throw new TagException("Negative Comment List Size");
+		}
+		
+		frames = new Hashtable(userCommentListLength);
+	}
+
+	private void loadFrames(AudioReader reader, boolean framingBit) throws IOException, TagException, EndOfPacketException {
+		int length = 0;
+		
+		String key;
+		
+		String value;
+		
+		int i, j, k;
+		
+		String keyBuffer = "";
+		
+		String valueBuffer = "";
+		
+		for (i = 0; i < userCommentListLength; i++) {
+			length = getInt();
+			
+			if (length < 0) {
+				throw new TagException("Negative String Size");
+			}
+
+			data = new byte[length];
+			
+			for (j = 0; j < length; j++) {
+				data[j] = (byte) getByte();
+			}
+			
+			k = 0;
+			
+			for (; k < data.length; k++) {
+				if (data[k] == '=') {
+					break;
+				}
+			}
+			key = new String(data, 0, k).toUpperCase();
+			value = con.convert(data, k + 1, data.length);
+			
+			if (key.equals(keyBuffer)) {
+				value = valueBuffer+", "+value;
+			}
+			
+			keyBuffer = new String(key);
+			valueBuffer = new String(value);
+			frames.put(key, value);
+		}
+		if (framingBit) {
+			if (getLittleEndian1() == 0) {
+				throw new TagException("No Ogg Tag");
+			}
+		}
+	}
+	
+	/**
+	 * Returns a single bit.
+	 *
+	 * @return                               the integer value of one bit
+	 * @exception IOException                if one bit can't be retrieved
+	 * @exception EndOfPacketExeption        if an end of packet occur
+	 */
+	public int getLittleEndian1() throws IOException, EndOfPacketException {
+		return reader.getLittleEndian1();
+	}
+
+	/**
+	 * Returns a single byte.
+	 *
+	 * @return                               the integer value of one bit
+	 * @exception IOException                if one bit can't be retrieved
+	 * @exception EndOfPacketExeption        if an end of packet occur
+	 */
+	public int getByte() throws IOException, EndOfPacketException {
+		if (reader instanceof VideoReader) {
+			return ((VideoReader) reader).get(8);
+		}
+		return reader.getLittleEndian(8);
+	}
+	
+	/**
+	 * Returns an int
+	 *
+	 * @return                               the integer value
+	 * @param i                              the length in bits
+	 * @exception IOException                if the bits can't be retrieved
+	 * @exception EndOfPacketExeption        if an end of packet occur
+	 */
+	public int getInt() throws IOException, EndOfPacketException {
+		if (reader instanceof VideoReader) {
+			return ((VideoReader) reader).get(8) | ((VideoReader) reader).get(8) << 8 | ((VideoReader) reader).get(8) << 16 | ((VideoReader) reader).get(8) << 24;
+		}
+		return reader.getLittleEndian(32);
+	}
+}
+
+

Added: trunk/rhea/com/meviatronic/zeus/helen/README.txt
===================================================================
--- trunk/rhea/com/meviatronic/zeus/helen/README.txt	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/helen/README.txt	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,23 @@
+	Helen, a Comment decoder created by Michael Scheerer.
+	Helen decoder (c) 2009 Michael Scheerer www.meviatronic.com
+
+	Many thanks to
+	Monty <monty at xiph.org> and
+	The XIPHOPHORUS Company http://www.xiph.org/ .
+	
+	Helen's UTF-8 decoding based on:
+	Self developed algorithm, therefore there's no
+	reference.
+	
+	Helen's tag information processing system is adapted from the
+	media information processing system of the Lightweight Java Media Framework
+	(www.ljmf.org).
+	
+	Summary:
+	
+	Advantages of Helen over the current reference decoder:
+	- the actual most advanced Comment decoder.
+	
+	Todo:
+ 	
+ 	Nothing to do.

Added: trunk/rhea/com/meviatronic/zeus/helen/Tag.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/helen/Tag.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/helen/Tag.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,196 @@
+/* Helena, a Comment decoder created by Michael Scheerer.
+ *
+ * Helena decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.helen;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * The <code>Tag</code> class provides methods to obtain the content of media tag
+ * informations, which describe possible extra informations of a media source.
+ * So it's possible to obtain, add and change tag informations with get and
+ * put methods. Predefined base hashkeys are defined in this class,
+ * but content related hashkeys must be defined inside derived
+ * classes. Note that all derived classes of this class are not used within
+ * this library itself. Instead media codec plug-ins of this library uses
+ * the tag system. Also the tag system can contain several tag formats like
+ * IDv1, IDv2 or Ogg Vorbis Tag, but a plug-in system of these different formats
+ * are not supported, because the tag system classes are referenced and instanced
+ * directly inside the codecs.
+ *
+ * <p>
+ * All tag related values of the hashkeys are <b>not</b> predefined with default values.
+ *
+ * <p>
+ * To create a hypothetical IDv2 tag plug-in it's required to derive
+ * this class according to the following listing:
+ *
+ * <blockquote>
+ * <pre>
+ * package org.ljmf.audio.codec.tag.id3v2;<p>
+ *
+ * import java.io.*;
+ * import java.util.*;
+ * import java.util.zip.*;<p>
+ *
+ * import org.ljmf.audio.codec.tag.*;<p>
+ *
+ * public final class MyIDv2Tag extends Tag {<p>
+ *
+ *     //====================<p>
+ *
+ *     public MyIDv2Tag(InputStream stream) throws IOException, TagException {
+ *         super();<p>
+ *
+ *         try {
+ *             readHeader(stream);
+ *         } catch (TagException e) {
+ *             close();
+ *             return;
+ *         }<p>
+ *
+ *         put(S_TAG_FORMAT, new String("ID3v2"));<p>
+ *
+ *         loadFrames(stream);<p>
+ *
+ *         buildKeyMapTable();<p>
+ *
+ *     }<p>
+ *
+ *     public String toString() {
+ *         // Override default implementation if neccessary.
+ *     }<p>
+ *
+ *     public Object clone() {
+ *         // Override default implementation if neccessary.
+ *     }<p>
+ *
+ *     //====================<p>
+ *
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * @author    Michael Scheerer
+ */
+public abstract class Tag extends Hashtable {
+	
+	/**
+	 * The predefined tag version key.
+	 */
+	public final static String S_TAG_FORMAT = "String tagFormat";
+
+	/**
+	 * The predefined tag value key.
+	 */
+	public final static String B_TAG = "Boolean tag";
+	
+	/**
+	 * The predefined album  value key.
+	 */
+	public final static String S_ALBUM = "String album";
+	
+	/**
+	 * The predefined artist value key.
+	 */
+	public final static String S_ARTIST = "String artist";
+	
+	/**
+	 * The predefined composer value key.
+	 */
+	public final static String S_COMPOSER = "String composer";
+	
+	/**
+	 * The predefined track (number) value key.
+	 */
+	public final static String S_TRACK = "String track";
+	
+	/**
+	 * The predefined year (of publishing) value key.
+	 */
+	public final static String S_YEAR = "String year";
+	
+	/**
+	 * The predefined date (of publishing) value key.
+	 */
+	public final static String S_DATE = "String date";
+	
+	/**
+	 * The predefined title value key.
+	 */
+	public final static String S_TITLE = "String title";
+	
+	/**
+	 * The predefined performer value key.
+	 */
+	public final static String S_PERFORMER = "String performer";
+	
+	/**
+	 * The predefined copyright text value key.
+	 */
+	public final static String S_COPYRIGHT = "String copyrightText";
+	
+	/**
+	 * The predefined genre text value key.
+	 */
+	public final static String S_GENRE = "String genre";
+		
+	/**
+	 * The predefined isrc (International Standard Recording Code) value key.
+	 */
+	public final static String S_ISRC = "String isrc";
+	
+	/**
+	 * The predefined encoder value key.
+	 */
+	public final static String S_ENCODER = "String encoder";
+	
+	
+	/**
+	 * Creates a new instance. Tag information is completely read the first time it
+	 * is requested and written after <code>update()</code>.
+	 *
+	 * @exception IOException   if I/O error occurs
+	 */
+	public Tag() throws IOException {}
+
+	/**
+	 * Frees all system resources, which are bounded to this object.
+	 */
+	public void close() {
+		clear();
+	}
+	
+	/**
+	 * Returns a <code>Hashtable</code> representation of this <code>Information</code> object.
+	 *
+	 * @return     a <code>Hashtable</code> representation of this <code>Information</code> object
+	 */
+	public Hashtable getHashtable() {
+		return (Hashtable) this.clone();
+	}
+}
+
+

Added: trunk/rhea/com/meviatronic/zeus/helen/TagException.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/helen/TagException.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/helen/TagException.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,50 @@
+/* Helena, a Comment decoder created by Michael Scheerer.
+ *
+ * Helena decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.helen;
+
+/**
+ * This <code>Exception</code> should be thrown if tag informations can't be
+ * extracted
+ *
+ * @author    Michael Scheerer
+ */
+public final class TagException extends Exception {
+
+	/**
+	 * Constructs an instance of <code>TagException</code>.
+	 */
+	public TagException() {
+	}
+
+	/**
+	 * Constructs an instance of <code>TagException</code>.
+	 *
+	 * @param s  the exception message
+	 */
+	public TagException(java.lang.String s) {
+		super(s);
+	}
+}
+

Added: trunk/rhea/com/meviatronic/zeus/pollux/MemoryImageSource.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/pollux/MemoryImageSource.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/pollux/MemoryImageSource.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,88 @@
+/* Pollux, a fast Theora decoder created by Michael Scheerer.
+ *
+ * Pollux decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.pollux;
+
+import java.awt.image.*;
+import java.util.*;
+
+/**
+ * This <code>MemoryImageSource</code> class is an optimized version of the
+ * origine <code>MemoryImageSource</code> class.
+ *
+ * @author Michael Scheerer
+ */
+final class MemoryImageSource implements ImageProducer {
+    private int width;
+    private int height;
+    private ColorModel model;
+    private Object pixels;
+    private int pixelscan;
+	private Output output;
+    
+    MemoryImageSource(int w, int h, ColorModel cm, Object pix, int scan, Output out) {
+		width = w;
+		height = h;
+		model = cm;
+		pixels = pix;
+		pixelscan = scan;
+		output = out;
+    }
+	
+    public void addConsumer(ImageConsumer ic) {
+    }
+
+    public boolean isConsumer(ImageConsumer ic) {
+        return false;
+    }
+
+    public void removeConsumer(ImageConsumer ic) {
+    }
+
+    public void requestTopDownLeftRightResend(ImageConsumer ic) {
+    }
+
+    public void startProduction(ImageConsumer ic) {
+		try {
+			synchronized(output) {
+				if(!output.display()) {
+					return;
+				}
+		 	}
+			ic.setDimensions(width, height);
+			ic.setColorModel(model);
+			ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES | ImageConsumer.SINGLEFRAME | ImageConsumer.SINGLEPASS);
+			ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
+			sendPixels(ic, 0, 0, width, height);
+		} catch (Exception e) {
+		}
+    }
+
+    private void sendPixels(ImageConsumer ic, int x, int y, int w, int h) {
+		int off = pixelscan * y + x;
+		ic.setPixels(x, y, w, h, model, ((int[]) pixels), off, pixelscan);
+    }
+}
+
+

Added: trunk/rhea/com/meviatronic/zeus/pollux/Output.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/pollux/Output.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/pollux/Output.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,448 @@
+/* Pollux, a fast Theora decoder created by Michael Scheerer.
+ *
+ * Pollux decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.pollux;
+
+import com.meviatronic.zeus.castor.*;
+
+import java.io.*;
+import java.awt.*;
+import java.awt.image.*;
+
+import org.xiph.ogg.*;
+
+/**
+ * The <code>Output</code> class provides all necessary Theora video display related methods including
+ * the color model of Theora. Until now (Theora 1.1),
+ * the two defined color models are only different by the gamma values,
+ * which are not used here. They may be used from output devices (monitor, etc).
+ *
+ * @author	Michael Scheerer
+ */
+abstract class Output {
+	// 4.2 Color Space Conversions and Parameters
+	//
+ 	// YCbCr -> RGB mapping
+ 	//
+	// variables are {rU, bV, bgV, rgU}
+	//
+	// Formulars 4.1 - 4.6 used, with exception of the later Y handling
+	//
+	// rU = (255 / 224) * 2 * (1 - Kr)
+	// bV = (255 / 224) * 2 * (1 - Kb)
+	// bgV = (255 / 224) * 2 * (Kb / Kg) * (1 - Kb)
+	// rgU = (255 / 224) * 2 * (Kr / Kg) * (1 - Kr)
+ 	//
+	// where:
+	// 1. Y = Kr * R + Kg * G + Kb * B
+	// 2. Kr + Kg + Kb = 1
+	// 3.
+	//
+	// 0. Kr = 0.2990, Kg = 0.5870, Kb = 0.1140 // Undefined
+	// 1. Kr = 0.2990, Kg = 0.5870, Kb = 0.1140 // Rec. ITU-R BT.470-6 System M,    Gamma = 2.2
+	// 2. Kr = 0.2990, Kg = 0.5870, Kb = 0.1140 // Rec. ITU-R BT.470-6 System B, G, Gamma = 2.67 instead 2.8
+	// 3. Kr = 0.2990, Kg = 0.5870, Kb = 0.1140 // Reserved
+	//
+	private final static float YUV_TO_RGB_CONVERSION[] = {
+		1280F/802F, 661005F/327680F, -128375F/327680F, -266395F/327680F
+	};
+	
+	final static byte CHROMA444 = 3;
+	final static byte CHROMA422 = 2;
+	final static byte CHROMA420 = 0;
+	
+	final static byte INTRA_FRAME = 0;
+	
+	private final static int CLIP_MIN = 260;
+	private final static int CLIP_MAX = 780;
+	private final static int CLIP_RANGE = 1040;
+	
+	private static int clip_16[] = new int[CLIP_RANGE];
+	private static int clip_8[] = new int[CLIP_RANGE];
+	private static int clip[] = new int[CLIP_RANGE];
+	
+	private static int Y[] = new int[256 + CLIP_RANGE];
+	
+	private static int[] rU = new int[256 + CLIP_RANGE];
+	private static int[] bV = new int[256 + CLIP_RANGE];
+	private static int[] rgU = new int[256 + CLIP_RANGE];
+	private static int[] bgV = new int[256 + CLIP_RANGE];
+	
+	
+	private static ColorModel DEFAULT = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
+    
+	private VideoReader info;
+	private int k, j;
+	private int u, v;
+	private int r, g, b, lum;
+	
+	private int dst[];
+	private int pixelRegion;
+	private int pixelOffset;
+	private int yCnt;
+	private int uvCnt;
+	private int clmCnt;
+	private int dstCnt;
+	private int lineCount;
+	private int pictureRegionX;
+	private int pictureRegionY;
+	private int pictureRegionW;
+	private int pictureRegionH;
+	private Rectangle imageRegion;
+	private Rectangle nullImageRegion;
+	private MemoryImageSource source;
+	
+	long granulepos;
+	int codedPictureHeight;
+	int chromaWidth;
+	int chromaHeight;
+	int chromaFormat;
+	int codedPictureWidth;
+	
+	short[] py, pu, pv;
+	
+	boolean skippedFrame;
+	int fType; // The frame type.
+	
+	static {
+		int i;
+		
+		for(i = -CLIP_MIN; i < CLIP_MAX; i++) {
+			clip_16[i + CLIP_MIN] = i >= 0 ? i <= 255 ? i << 16 : 0xFF0000 : 0;
+			clip_8[i + CLIP_MIN] = i >= 0 ? i <= 255 ? i << 8 : 0xFF00 : 0;
+			clip[i + CLIP_MIN] = i >= 0 ? i <= 255 ? i : 0xFF : 0;
+		}
+		for(i = 0; i < 256; i++) {
+			Y[i] = (int) (255F / 219F * (i - 16) + CLIP_MIN);
+			rU[i] = (int) (YUV_TO_RGB_CONVERSION[0] * (i - 128));
+			bV[i] = (int) (YUV_TO_RGB_CONVERSION[1] * (i - 128));
+			bgV[i] = (int) (YUV_TO_RGB_CONVERSION[2] * (i - 128));
+			rgU[i] = (int) (YUV_TO_RGB_CONVERSION[3] * (i - 128));
+
+		}
+	}
+	
+	/**
+	 * Constructs an instance of <code>Decoder</code> with a <code>MediaInformation</code>
+	 * object containing all necessary informations about the media source.
+	 *
+	 * @param info     the <code>VideoReader</code> object containing all
+	 *      necessary informations about the media source
+	 */
+	Output(VideoReader info) {
+		
+		this.info = info;
+		
+		codedPictureHeight = info.codedPictureHeight;
+		chromaFormat = info.chromaFormat;
+		codedPictureWidth = info.codedPictureWidth;
+		pictureRegionX = info.pictureRegionX;
+		pictureRegionY = info.pictureRegionY;
+		pictureRegionW = info.pictureRegionW;
+		pictureRegionH = info.pictureRegionH;
+		dst = new int[codedPictureWidth * codedPictureHeight];
+		imageRegion = new Rectangle(pictureRegionX, pictureRegionY, pictureRegionW, pictureRegionH);
+		nullImageRegion = new Rectangle(0, 0, 0, 0);
+		source = new MemoryImageSource(codedPictureWidth, codedPictureHeight, DEFAULT, dst, codedPictureWidth, this);
+	}
+	
+	private void progressive420() {
+		int yCntBuf, uvCntBuff, dstCntBuf;
+		
+		for (j = pixelOffset; j < pixelRegion; j += 4) {
+	  		lum = Y[py[yCnt]];
+      		u = pu[uvCnt];
+			v = pv[uvCnt];
+			r = rU[u];
+			g = rgU[u] + bgV[v];
+			b = bV[v];
+	  		dst[dstCnt] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			yCntBuf = yCnt + codedPictureWidth;
+			dstCntBuf = dstCnt - codedPictureWidth;
+
+			lum = Y[py[yCntBuf]];
+			
+			dst[dstCntBuf] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			yCntBuf = yCnt + 1;
+			dstCntBuf = dstCnt + 1;
+
+			lum = Y[py[yCntBuf]];
+			
+			dst[dstCntBuf] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			yCntBuf = yCntBuf + codedPictureWidth;
+			dstCntBuf = dstCntBuf - codedPictureWidth;
+
+			lum = Y[py[yCntBuf]];
+			
+			dst[dstCntBuf] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			clmCnt += 2;
+			yCnt += 2;
+			dstCnt += 2;
+			uvCnt++;
+			if (clmCnt == codedPictureWidth) {
+				clmCnt = 0;
+				yCnt += codedPictureWidth;
+				dstCnt -= 3 * codedPictureWidth;
+			}
+		}
+	}
+	
+	private void progressive422() {
+		int yCntBuf, uvCntBuff, dstCntBuf;
+		
+		for (j = pixelOffset; j < pixelRegion; j += 4) {
+	  		lum = Y[py[yCnt]];
+      		u = pu[uvCnt];
+			v = pv[uvCnt];
+			r = rU[u];
+			g = rgU[u] + bgV[v];
+			b = bV[v];
+	  		dst[dstCnt] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			yCntBuf = yCnt + codedPictureWidth;
+			dstCntBuf = dstCnt - codedPictureWidth;
+
+			lum = Y[py[yCntBuf]];
+			
+			dst[dstCntBuf] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			yCntBuf = yCnt + 1;
+			dstCntBuf = dstCnt + 1;
+
+			lum = Y[py[yCntBuf]];
+			
+			u = pu[uvCnt];
+			v = pv[uvCnt];
+			r = rU[u];
+			g = rgU[u] + bgV[v];
+			b = bV[v];
+
+			dst[dstCntBuf] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			yCntBuf = yCntBuf + codedPictureWidth;
+			dstCntBuf = dstCntBuf - codedPictureWidth;
+
+			lum = Y[py[yCntBuf]];
+			
+			dst[dstCntBuf] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			clmCnt += 2;
+			yCnt += 2;
+			dstCnt += 2;
+			uvCnt++;
+			if (clmCnt == codedPictureWidth) {
+				uvCnt += chromaWidth;
+				clmCnt = 0;
+				yCnt += codedPictureWidth;
+				dstCnt -= 3 * codedPictureWidth;
+			}
+		}
+	}
+	
+	private void progressive444() {
+		int yCntBuf, uvCntBuff, dstCntBuf;
+		
+		for (j = pixelOffset; j < pixelRegion; j += 4) {
+	  		lum = Y[py[yCnt]];
+      		u = pu[uvCnt];
+			v = pv[uvCnt];
+			r = rU[u];
+			g = rgU[u] + bgV[v];
+			b = bV[v];
+	  		dst[dstCnt] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			yCntBuf = yCnt + codedPictureWidth;
+			dstCntBuf = dstCnt - codedPictureWidth;
+
+			lum = Y[py[yCntBuf]];
+			uvCntBuff = uvCnt + chromaWidth;
+			u = pu[uvCntBuff];
+			v = pv[uvCntBuff];
+			r = rU[u];
+			g = rgU[u] + bgV[v];
+			b = bV[v];
+			
+			dst[dstCntBuf] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			yCntBuf = yCnt + 1;
+			dstCntBuf = dstCnt + 1;
+
+			lum = Y[py[yCntBuf]];
+			uvCnt++;
+			u = pu[uvCnt];
+			v = pv[uvCnt];
+			r = rU[u];
+			g = rgU[u] + bgV[v];
+			b = bV[v];
+			
+			dst[dstCntBuf] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			yCntBuf = yCntBuf + codedPictureWidth;
+			dstCntBuf = dstCntBuf - codedPictureWidth;
+
+			lum = Y[py[yCntBuf]];
+			uvCntBuff = uvCnt + chromaWidth; // still incremented
+			u = pu[uvCntBuff];
+			v = pv[uvCntBuff];
+			r = rU[u];
+			g = rgU[u] + bgV[v];
+			b = bV[v];
+
+			dst[dstCntBuf] = clip_16[lum + r] | clip_8[lum + g] | clip[lum + b];
+			
+			clmCnt += 2;
+			yCnt += 2;
+			dstCnt += 2;
+			uvCnt++;
+			if (clmCnt == codedPictureWidth) {
+				uvCnt += chromaWidth;
+				clmCnt = 0;
+				yCnt += codedPictureWidth;
+				dstCnt -= 3 * codedPictureWidth;
+			}
+		}
+	}
+	
+	abstract boolean display();
+
+	void display(int offset, int range) {
+		pixelRegion = range;
+		pixelOffset = offset;
+		clmCnt = range % codedPictureWidth;
+		yCnt = offset;
+		uvCnt = offset >> 2;
+		if (chromaFormat == CHROMA422) {
+			uvCnt = offset >> 1;
+		} else if (chromaFormat == CHROMA444) {
+			uvCnt = offset;
+		}
+		dstCnt = codedPictureWidth * (codedPictureHeight - offset / codedPictureWidth - 1);
+		
+		if (chromaFormat == CHROMA420) {
+			progressive420();
+		} else if (chromaFormat == CHROMA422) {
+			progressive422();
+		} else {
+			progressive444();
+		}
+	}
+	
+	/**
+	 * Returns the image region boundary to update an image region.
+	 * With this boundary the actual image region
+	 * of the selected image can be displayed
+	 * on a video screen display with more performance
+	 * than updating the hole image.
+	 *
+	 * @return  the image region boundary to update an image region
+	 */
+	public final Rectangle getImageRegion() {
+		if (skippedFrame) {
+			return nullImageRegion;
+		}
+		return imageRegion;
+	}
+	
+	abstract void decodeImage() throws IOException, EndOfMediaException, EndOfPacketException;
+	
+	public final boolean isKeyFrame() {
+		return fType == INTRA_FRAME ? true : false;
+  	}
+	
+	public final ImageProducer synthesis(Packet op) throws IOException, EndOfPacketException {
+    	info.loadPacket(op.packetBase, op.packet, op.bytes);
+		
+		synchronized(this) {
+			decodeImage();
+		}
+		
+		if(op.granulepos > -1){
+        	granulepos = op.granulepos;
+	  	} else {
+		  	if (granulepos == -1){
+          		granulepos = 0;
+        	} else {
+				if (fType == INTRA_FRAME){
+            		long frames = granulepos & VideoReader.BITMASK[info.keyFrameNumberGranuleShift];
+					
+					granulepos >>>= info.keyFrameNumberGranuleShift;
+            		granulepos += frames + 1;
+            		granulepos <<= info.keyFrameNumberGranuleShift;
+          		} else {
+			  		granulepos++;
+		  		}
+        	}
+		}
+		CropImageFilter cropFilter = new CropImageFilter(pictureRegionX, pictureRegionY, pictureRegionW, pictureRegionH);
+		return new FilteredImageSource(source, cropFilter);
+	}
+	
+	public final double granuleTime(long granulePosition) {
+		if(granulePosition >= 0) {
+			return getFrameCount(granulePosition, info.keyFrameNumberGranuleShift, 0) / info.frameRate;
+    	}
+    	return -1;
+  	}
+	
+	private static int getFrameCount (long granulePosition, int keyFrameNumberGranuleShift, int versionRevisionNumber) {
+		if (versionRevisionNumber > 0) {
+			return (int) (granulePosition & VideoReader.BITMASK[keyFrameNumberGranuleShift]) + (int) (granulePosition >>> keyFrameNumberGranuleShift) - 1;
+		}
+		return (int) (granulePosition & VideoReader.BITMASK[keyFrameNumberGranuleShift]) + (int) (granulePosition >>> keyFrameNumberGranuleShift);
+	}
+
+	/**
+	 * Frees all system resources, which are bounded to this object.
+	 */
+	public void close() {
+		dst = null;
+		imageRegion = null;
+		nullImageRegion = null;
+		py = null;
+		pu = null;
+		pv = null;
+	}
+	
+	final int get1() throws IOException, EndOfPacketException {
+		return info.get1();
+	}
+	
+	final int get(int i) throws IOException, EndOfPacketException {
+		return info.get(i);
+	}
+
+	final int getCodeWord(int bookNumber) throws IOException, EndOfPacketException {
+		return info.getCodeWord(bookNumber);
+	}
+	
+	final static int ilog(int v) {
+		return AudioReader.ilog(v);
+	}
+}
+
+

Added: trunk/rhea/com/meviatronic/zeus/pollux/README.txt
===================================================================
--- trunk/rhea/com/meviatronic/zeus/pollux/README.txt	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/pollux/README.txt	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,93 @@
+	Pollux, a fast Theora decoder created by Michael Scheerer.
+	Pollux decoder (c) 2009 Michael Scheerer www.meviatronic.com
+
+	Many thanks to
+	Monty <monty at xiph.org> and
+	The XIPHOPHORUS Company http://www.xiph.org/ .
+	
+	Pollux's IDCT based on:
+	The official Theora specification.
+	
+	Features of Pollux's enhanced IDCT:
+	- inplacing.
+ 	- higher degree of content adaptive calculation.
+ 	  Dr. m. m. Timothy B. Terriberry pointed out, that this approach is only helpful in case
+ 	  of systems and compilers, which don't have or exploit
+ 	  the SIMD (Single Instruction Multiple Data) computer architecture.
+ 	
+ 	Pollux's colorspace transformation based on:
+	The official Theora specification.
+	
+	Pollux's CRC32 based on (but here used inside the Ogg Framing):
+	public domain code by
+	Ross Williams (ross at guest.adelaide.edu.au).
+	A 32 bit CRC value (direct algorithm, initial val and final XOR = 0, generator polynomial=0x04c11db7) is used.
+	The value is computed over the entire header (with the CRC field in the header set to zero)
+	and then continued over the page. The CRC field is then filled with the computed value.
+
+	Pollux's huffman decoding based on:
+ 	Self developed algorithm (deflated binary tree approach -
+	a kind of a 2 pow n compression), therefore there's no reference.
+	Dr. m. m. Timothy B. Terriberry pointed out, that this kind of approach is at least since 1993 a
+	reinvention:
+	R. Hashemian, "High Speed Search and Memory Efficient
+    Huffman Coding," 1993.
+
+	Pollux's bitstream decoding based on:
+ 	Self developed algorithm, therefore there's no reference.
+ 	
+	Summary:
+	
+	Advantages of Pollux over the current reference decoder (libTheora 1.1.1):
+	- content adaptive color space transformation.
+ 	- content adaptive block copying.
+ 	- content adaptive motion prediction (sparseDC mode).
+ 	- higher degree of content adaptive IDCT on non SIMD architectures.
+ 	- higher degree of content adaptive edge detection and deblock filtering.
+ 	- sparseDC mode.
+ 	  Dr. m. m. Timothy B. Terriberry pointed out, that there is
+ 	  a separation of the MC from the DCT in developing for a future reference decoder version,
+ 	  which even avoids such a special sparseDC mode with the same amount of
+ 	  reducing the calculation amount.
+ 	- avoiding a two pass coefficient decoding.
+ 	
+ 	Advantages of Pollux over an older Java version (called JTheora) of the reference decoder:
+ 	- drastical reduced binary or bytecode size
+ 	  (from 80 Kbyte Java bytecode ripped of encoder stuff to only 50 Kbyte).
+ 	- support of the specified truncated packet operation.
+ 	- better huffman decoding.
+	- memory consumption is lower (under Java according to the taskmanager).
+	- performance consumption is lower (under Java according to the taskmanager).
+ 	- "feeled" performance improvement of full scaled video playback is nearly 80%
+ 	  on a single core Pentium M 1.4 GHZ machine.
+ 	- content adaptive color space transformation.
+ 	- content adaptive motion prediction (sparseDC mode).
+ 	- higher degree of content adaptive IDCT.
+ 	- higher degree of content adaptive edge detection and deblocking.
+ 	- color space transformation is working in a separate thread - yielding a
+ 	  better load balancing of the CPU utilization on multicore/multithread machines
+ 	  or in case of CPU loads of over 100%.
+ 	- sparseDC mode.
+ 	- support of the pixel formats 4:4:4 and 4:2:2.
+ 	- elimination of the "64 * number of blocks"-fold performance bottleneck if-condition
+ 	  inside the coefficient decoding.
+ 	
+ 	The code size and/or memory consumption may be of interest for
+ 	firmware developers of hardware players.
+ 	
+ 	A firmware port of Pollux should replace the recursions during the
+ 	Huffman decoder initialization. Under Java, this recursion based initialization
+ 	is faster than the non recursion version.
+ 	
+ 	Todo:
+ 	
+ 	Exact performance tests against the actual reference decoder.
+ 	
+ 	Because of the small codesize of Pollux, the decoder may
+ 	be the right one for e.g. firmware/HDL/ASIC developers.
+ 	
+ 	
+ 	Appreciations:
+ 	
+ 	Very thanks to Dr. m. m. Timothy B. Terriberry for reviewing and error correcting
+ 	the README and Pollux decoder.

Added: trunk/rhea/com/meviatronic/zeus/pollux/TheoraDecoder.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/pollux/TheoraDecoder.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/pollux/TheoraDecoder.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,2416 @@
+/* Pollux, a fast Theora decoder created by Michael Scheerer.
+ *
+ * Pollux decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.pollux;
+
+import com.meviatronic.zeus.castor.*;
+
+import java.io.*;
+
+/**
+ * The <code>TheoraDecoder</code> class is the main video decoder class.
+ *
+ * @author  Michael Scheerer
+ */
+public final class TheoraDecoder extends Output  {
+	
+	private final static int CLIP_MIN = 33024;
+	private final static int CLIP_MAX = 33024;
+	private final static int CLIP_RANGE = 66048;
+	
+	private static short clip[] = new short[CLIP_RANGE];
+	
+	private final static int FILTER_MIN = 256;
+	private final static int FILTER_RANGE = 512;
+	
+	private final static int PLANE_CLIP_MIN = 16;
+	private final static int PLANE_CLIP_MAX = 16;
+	private final static int PLANE_CLIP_RANGE = 32;
+	
+	private final static byte INTER_NOMV = 0;
+	private final static byte INTRA = 1;
+	private final static byte INTER_MV = 2;
+	private final static byte INTER_MV_LAST = 3;
+	private final static byte INTER_MV_LAST2 = 4;
+	private final static byte INTER_GOLDEN_NOMV = 5;
+	private final static byte INTER_GOLDEN_MV = 6;
+	private final static byte INTER_MV_FOUR = 7;
+	
+	private final static byte INTRA_FRAME = 0;
+	private final static byte PREVIOUS_REFERENCE_FRAME_INDEX = 1;
+	private final static byte GOLDEN_REFERENCE_FRAME_INDEX = 2;
+	
+	private final static int C1 = 64277;
+	private final static int S7 = 64277;
+	private final static int C2 = 60547;
+	private final static int S6 = 60547;
+	private final static int C3 = 54491;
+	private final static int S5 = 54491;
+	private final static int C4 = 46341;
+	private final static int S4 = 46341;
+	private final static int C5 = 36410;
+	private final static int S3 = 36410;
+	private final static int C6 = 25080;
+	private final static int S2 = 25080;
+	private final static int C7 = 12785;
+	private final static int S1 = 12785;
+		
+	private final static short[] ZERO_SHORTS = new short[64];
+	
+	private final static byte NATURAL_ORDER_SCAN[] = {
+		0, 1, 2, 3, 4, 5, 6, 7,
+		8, 9, 10, 11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20, 21, 22, 23,
+		24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39,
+		40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55,
+		56, 57, 58, 59, 60, 61, 62, 63,
+		63, 63, 63, 63, 63, 63, 63, 63,
+		63, 63, 63, 63, 63, 63, 63, 63,
+		63, 63, 63, 63, 63, 63, 63, 63,
+		63, 63, 63, 63, 63, 63, 63, 63,
+		63, 63, 63, 63, 63, 63, 63, 63,
+		63, 63, 63, 63, 63, 63, 63, 63,
+		63, 63, 63, 63, 63, 63, 63, 63,
+		63, 63, 63, 63, 63, 63, 63, 63
+	};
+	private final static byte INVERSE_ZIG_ZAG_SCAN[] = {
+		 0,  1,  8, 16,  9,  2,  3, 10,
+		17, 24, 32, 25, 18, 11,  4,  5,
+		12, 19, 26, 33, 40, 48, 41, 34,
+		27, 20, 13,  6,  7, 14, 21, 28,
+		35, 42, 49, 56, 57, 50, 43, 36,
+		29, 22, 15, 23, 30, 37, 44, 51,
+		58, 59, 52, 45, 38, 31, 39, 46,
+		53, 60, 61, 54, 47, 55, 62, 63
+	};
+	private final static byte ZIG_ZAG_TO_NATURAL_ORDER_ROW_MAPPING[] = {
+		 0,  0,  1,  2,  2,  2,  2,  2,
+		 2,  3,  4,  4,  4,  4,  4,  4,
+		 4,  4,  4,  4,  5,  6,  6,  6,
+		 6,  6,  6,  6,  6,  6,  6,  6,
+		 6,  6,  6,  7,  7,  7,  7,  7,
+		 7,  7,  7,  7,  7,  7,  7,  7,
+		 7,  7,  7,  7,  7,  7,  7,  7,
+		 7,  7,  7,  7,  7,  7,  7,  7
+	};
+	// [yRemainder][xRemainder][bi]
+	private final static byte SUPERBLOCK_X_BLOCKS_OFFSET[][][] = {
+	  {{0},
+		   {0, 1},
+				  {0, 1, 2},
+				  			{0, 1, 2, 3}},
+	  {{0,
+	    0},
+		   {0, 1,
+		    1, 0},
+				  {0, 1, 1,
+				   0, 2, 2},
+							{0, 1, 1, 0,
+							 3, 2, 2, 3}},
+	  {{0,
+	    0,
+	    0},
+		   {0, 1,
+		    1, 0,
+		    0, 1},
+				  {0, 1, 1,
+				   0, 0, 1,
+				   2, 2, 2},
+				  			{0, 1, 1, 0,
+							 0, 1, 2, 3,
+							 3, 2, 2, 3}},
+	  {{0,
+	    0,
+	    0,
+	    0},
+		   {0, 1,
+			1, 0,
+	      	0, 0,
+		  	1, 1},
+			  	  {0, 1, 1,
+				   0, 0, 0,
+				   1, 1, 2,
+				   2, 2, 2},
+							{0, 1, 1, 0,
+							 0, 0, 1, 1,
+							 2, 2, 3, 3,
+							 3, 2, 2, 3}}
+	};
+	// [yRemainder][xRemainder][bi]
+	private final static byte SUPERBLOCK_Y_BLOCKS_OFFSET[][][] = {
+	  {{0},
+		   {0, 0},
+				  {0, 0, 0},
+				  			{0, 0, 0, 0}},
+	  {{0,
+	    1},
+		   {0, 0,
+		    1, 1},
+				  {0, 0, 1,
+				   1, 1, 0},
+							{0, 0, 1, 1,
+							 1, 1, 0, 0}},
+	  {{0,
+	    1,
+	    2},
+		   {0, 0,
+		    1, 1,
+		    2, 2},
+				  {0, 0, 1,
+				   1, 2, 2,
+				   2, 1, 0},
+							{0, 0, 1, 1,
+							 2, 2, 2, 2,
+							 1, 1, 0, 0}},
+	  {{0,
+	    1,
+	    2,
+	    3},
+		   {0, 0,
+		    1, 1,
+		    2, 3,
+		    3, 2},
+				  {0, 0, 1,
+				   1, 2, 3,
+				   3, 2, 2,
+				   3, 1, 0},
+							{0, 0, 1, 1,
+							 2, 3, 3, 2,
+							 2, 3, 3, 2,
+							 1, 1, 0, 0}}
+	};
+	private final static byte HUFFMANCODETABLE7_7RSTART[] = {
+		1, 2, 4, 6, 10, 18, 34
+	};
+	private final static byte HUFFMANCODETABLE7_7RBITS[] = {
+		0, 1, 1, 2, 3, 4, 12
+	};
+	private final static byte HUFFMANCODETABLE7_11RSTART[] = {
+		1, 3, 5, 7, 11, 15
+	};
+	private final static byte HUFFMANCODETABLE7_11RBITS[] = {
+		1, 1, 1, 2, 2, 4
+	};
+	private final static byte HUFFMANCODETABLE7_14[][] = {
+		{0, 0, 0, 0, 0, 0, 0, 0},
+		{3, 4, 2, 0, 1, 5, 6, 7}, {3, 4, 0, 2, 1, 5, 6, 7},
+		{3, 2, 4, 0, 1, 5, 6, 7}, {3, 2, 0, 4, 1, 5, 6, 7},
+		{0, 3, 4, 2, 1, 5, 6, 7}, {0, 5, 3, 4, 2, 1, 6, 7}
+	};
+	// Negative values assign to table columns and the to read bit length,
+	// with the exception of -2, where column is 2 and the to read bit length only 1.
+	// Positive values must be subtracted with 31 to produce the final result.
+	// The lookup procedure starts with the reading of 3 bits. These values are the indices for column 0.
+	private final static byte HUFFMANCODETABLE7_23[][] = {
+		{31, 32, 30, -1, -2, -3, -4, -5},
+		{33, 29},
+		{34, 28},
+		{35, 27, 36, 26, 37, 25, 38, 24},
+		{39, 23, 40, 22, 41, 21, 42, 20, 43, 19, 44, 18, 45, 17, 46, 16},
+		{47, 15, 48, 14, 49, 13, 50, 12, 51, 11, 52, 10, 53,  9, 54,  8, 55,  7, 56,  6, 57,  5, 58,  4, 59,  3, 60,  2, 61,  1, 62,  0},
+	};
+	private final static byte TOKEN_TABLE7_33[][] = {
+		{0, 0, 0, 2, 3,  4, 12, 3, 6, 0,  0, 0,  0, 1, 1, 1, 1, 2, 3,  4,  5,  6, 10, 1, 1, 1, 1, 1, 3,  4,  2, 3},
+		{0, 0, 0, 3, 7, 15, -1, 0, 0, 1, -1, 2, -2, 3, 4, 5, 6, 7, 9, 13, 21, 37, 69, 1, 2, 3, 4, 5, 6, 10,  0, 1},
+		{0, 0, 0, 0, 0, 0,   0, 1, 1, 2,  2, 2,  2, 2, 2, 2, 2, 2, 2,  2,  2,  2,  2, 3, 3, 3, 3, 3, 3,  3,  4, 4}
+	};
+	private final static byte HUFFMAN_GROUP_TABLE7_42[] = {
+		0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+		4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+		4, 4, 4, 4
+	};
+	private final static byte CODE_MODE_TABLE7_46[] = {
+		1, 0, 1, 1, 1, 2, 2, 1
+	};
+	private final static short DCPREDICTORS_WEIGHTS_AND_DIVISORS_TABLE7_47[][] = {
+		{ 0,   0,   0,   0,   0},
+		{ 1,   0,   0,   0,   1},
+		{ 1,   0,   0,   0,   1},
+		{ 1,   0,   0,   0,   1},
+		{ 1,   0,   0,   0,   1},
+		{ 1,   1,   0,   0,   2},
+		{ 0,   1,   0,   0,   1},
+		{29, -26,  29,   0,  32},
+		{ 1,   0,   0,   0,   1},
+		{75,  53,   0,   0, 128},
+		{ 1,   1,   0,   0,   2},
+		{75,   0,  53,   0, 128},
+		{ 1,   0,   0,   0,   1},
+		{75,   0,  53,   0, 128},
+		{ 3,  10,   3,   0,  16},
+		{29, -26,  29,   0,  32}
+	};
+	// [yRemainder][xRemainder][bi] // index plus/minus one to avoid -0 / +0!
+	// Note, that Hilbert curve pattern was choosen,
+	// because the fractal dimension of a Hilbert curve aproximates to 2.
+	private final static byte CHROMA_420_BI_TO_MBI_MAPPING[][][] = {
+	   {{ 1            },
+	    { 1,  2        },
+	    { 1,  2,  3    },
+	    { 1,  2,  3,  4}},
+	   {{ 1,  2,       },
+	    { 1,  4,  3,  2},
+	    { 1,  4,  3,  2,
+	      6,  5        },
+	    { 1,  4,  3,  2,
+	      7,  6,  5,  8}},
+	   {{ 1,  2, -1    },
+	    { 1,  4,  3,  2,
+	     -1, -2       },
+	    { 1,  4,  3,  2,
+	     -1, -2, -3,
+	      6,  5        },
+	    { 1,  4,  3,  2,
+	     -1, -2,
+	     -3, -4,
+	      7,  6,  5,  8}},
+	   {{ 1,  2, -1, -2},
+	    { 1,  4,  3,  2,
+	     -1, -2, -3, -4},
+	    { 1,  4,  3,  2,
+	     -1, -2, -3, -4,
+	     -5, -6,  6,  5},
+	    { 1,  4,  3,  2,
+	     -1, -2, -3, -4,
+	     -5, -6, -7, -8,
+	      7,  6,  5,  8}}
+	};
+	// [yRemainder / 2][xRemainder][bi] // index plus/minus one to avoid -0 / +0!
+	// Note, that Hilbert curve pattern was choosen,
+	// because the fractal dimension of a Hilbert curve aproximates to 2.
+	private final static byte CHROMA_422_BI_TO_MBI_MAPPING[][][] = {
+	   {{ 1,  1        },
+	    { 1,  2,  2,  1},
+	    { 1,  2,  2,  1,
+	      3,  3,       },
+	    { 1,  2,  2,  1,
+	      4,  3,  3,  4}},
+	   {{ 1,  1,  2,  2},
+	    { 1,  4,  4,  1,
+	      2,  2,  3,  3},
+	    { 1,  4,  4,  1,
+	      2,  2,  3,  3,
+	      6,  6,  5,  5},
+	    { 1,  4,  4,  1,
+	      2,  2,  3,  3,
+	      6,  6,  7,  7,
+	      8,  5,  5,  8}}
+	};
+	// The first index gets 1 if the superblock has 4 macro blocks or is truncated
+	// along the x-axis or 0 if the the superblock is truncated along the y-axis,
+	// the second index gets the luma macro block indices (lmbi) and the third index
+	// gets the block indices (coding order) and the result are raster ordered block indices.
+	private final static byte CODING_ORDER_TO_BLOCK_RASTER_ORDER[][][] = {
+	   {{ 0,  1,  3,  2},
+	    { 2,  3,  1,  0}},
+	   {{ 0,  1,  3,  2},
+	    { 0,  3,  1,  2},
+	    { 0,  3,  1,  2},
+	    { 2,  3,  1,  0}}
+	};
+	// The first index gets 1 if the superblock has 4 macro blocks or is truncated
+	// along the x-axis or 0 if the the superblock is truncated along the y-axis,
+	// the second index gets the block indices (coding order).
+	private final static byte CHROMA_422_MOTIONVECTOR_SELECTION[][] = {
+	    { 4,  4,  5,  5,
+	      5,  5,  4,  4},
+	    { 4,  4,  5,  5,
+	      4,  5,  5,  4,
+	      4,  5,  5,  4,
+	      5,  5,  4,  4}
+	};
+	// [chromaDecimation][mva + 31]
+	private final static byte MOTIONVECTOR_MAPPING_BASE[][] = {
+	   {-15, -15, -14, -14, -13, -13, -12, -12, -11, -11, -10, -10,  -9,  -9,  -8,
+	     -8,  -7,  -7,  -6,  -6,  -5,  -5,  -4,  -4,  -3,  -3,  -2,  -2,  -1,  -1,   0,
+	      0,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,
+	      8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15},
+	   { -7,  -7,  -7,  -7,  -6,  -6,  -6,  -6,  -5,  -5,  -5,  -5,  -4,  -4,  -4,
+	     -4,  -3,  -3,  -3,  -3,  -2,  -2,  -2,  -2,  -1,  -1,  -1,  -1,   0,   0,   0,
+	      0,   0,   0,   0,   1,   1,   1,   1,   2,   2,   2,   2,   3,   3,   3,   3,
+ 	      4,   4,   4,   4,   5,   5,   5,   5,   6,   6,   6,   6,   7,   7,   7,   7}
+	};
+	// [chromaDecimation][mva + 31]
+	private final static byte MOTIONVECTOR_MAPPING_DIFF[][] = {
+	   { -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,
+ 	      0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,
+ 	      0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,
+ 	      0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1},
+	   { -1,  -1,  -1,   0,  -1,  -1,  -1,   0,  -1,  -1,  -1,   0,  -1,  -1,  -1,
+ 	      0,  -1,  -1,  -1,   0,  -1,  -1,  -1,   0,  -1,  -1,  -1,   0,  -1,  -1,  -1,
+ 	      0,   1,   1,   1,   0,   1,   1,   1,   0,   1,   1,   1,   0,   1,   1,   1,
+ 	      0,   1,   1,   1,   0,   1,   1,   1,   0,   1,   1,   1,   0,   1,   1,   1}
+	};
+	private final static short[] ONE_HUNDRED_TWENTYEIGHT_INTS = {
+		128, 128, 128, 128, 128, 128, 128, 128
+	};
+	private short[][][][] qmat; // A 64-element array of quantization values for each DCT coefficient in natural order.
+	private boolean initialized;
+	private short[][] image; // An array containing the contents of all planes of the current frame.
+	private short[][] ref; // An array containing the contents of all planes of the reference frame (past frame).
+	private short[][] goldRef; // An array containing the contents of all planes of the golden reference frame (past key frame).
+	private byte[] mAlphabet = new byte[8]; // Integer array - The list of modes corresponding to each Huffman code.
+	private int nbs; // The number of blocks. // Porting problem: Should be long
+	private int nsbs; // The number of super blocks.
+	private int nlsbs; // The number of luma plane super blocks.
+	private int ncsbs; // The number of chroma plane super blocks.
+	private int nmbs; // The number of macro blocks.
+	private int fType; // The frame type.
+	private int nqis; // The number of qi values.
+	private int[] qis = new int[3]; // A NQIS-element array of qi values.
+	private byte[] tis; // A NSBS*NBSPS-element array of the current token index for each block.
+	private byte[][] bCoded; // A NSBS/NBSPS array indicating which blocks are coded.
+	private int[] cbIndex; // A NBS-element array of flags (sbi | bi) coding coded block indices. // Porting problem: Should be long[]
+	private Node qcbIndex;
+	private Node root;
+	private int[] ncbIndex; // A NBS-element array of flags (sbi | bi) coding not coded intra frame block indices. // Porting problem: Should be long[]
+	private int[] cifbIndex; // A NBS-element array of flags (sbi | bi) coding coded intra frame block indices. // Porting problem: Should be long[]
+	private int[] ncifbIndex; // A NBS-element array of flags (sbi | bi) coding not coded block indices. // Porting problem: Should be long[]
+	private int[] mbiToSbiLmbiMapping; // A NMBS-element array of flags (sbi | lmbi | ySbRemainder / 2) coding macro block indices.
+	private int[] biToMbiMapping; // A NSBS*NBSPS array of macro block indices.
+	private int[][][] rasterOrderToCodedOrderMapping; // A NPLS/NBY/NBX array of flags (sbi | bi).
+	private byte[] mbMode; // A NMBS-element array of coding modes for each macro block.
+	private byte[][][] mVects; // A NMBS/NBSPMB/MVECXY array of motion vectors.
+	private byte[] qiis; // A NBS-element array of qii values for each block.
+	private int ncbs; // Number of coded blocks. // Porting problem: Should be long
+	private int nncbs; // Number of not coded blocks. // Porting problem: Should be long
+	private short[][] coeffs; // A NSBS*NBSPS/64 array of quantized DCT coefficient values for each block in zig-zag order.
+	private byte[] nCoeffs; // A NSBS*NBSPS-element array of the coefficient count for each block.
+	private short[] lastDc = new short[3]; // A 3-element array containing the most recently decoded DC value, one for inter mode and for each reference frame.
+	private short[] coeffsValues = new short[4]; // A 4-element array of the neighboring DC coefficient values to apply to each DC value.
+	private int[] spipp; // A NSBS-element array of the spi's of each single plane.
+	private int[] pli; // A NSBS-element array of the plane index values.
+	private int y0, y1, y2, y3, y4, y5, y6, y7; // An 8-element array of 1D iDCT input values.
+	private int[][] planeWidthClip; // An array for clipping/clamping plane sizes for each plane. The third plane clip array is a reused second one.
+	private int[][] planeHeightClip; // An array for clipping/clamping plane sizes for each plane. The third plane clip array is a reused second one.
+	private byte[] lflims; // A 64-element array of loop filter limit values.
+	private byte[] sbpCodedBits; // Bit string of a decoded set of partial coded super block flags. // Porting problem: Should be long
+	private byte[] sbfCodedBits; // Bit string of a decoded set of full coded super block flags. // Porting problem: Should be long
+	private byte[] bits; // Bit string of a decoded set of flags. // Porting problem: Should be long
+	private int eobs; // The remaining length of the current EOB run. // Porting problem: Should be long
+	private int[] blockCoordinateX; // A NSBS*NBSPS-element array of the horizontal pixel indices of the lower-left corner of the current block.
+	private int[] blockCoordinateY; // A NSBS*NBSPS-element array of the vertical pixel indices of the lower-left corner of the current block.
+	private short[][] lflim = new short[64][FILTER_RANGE];
+	private int[] dqc = new int[64]; // An array of dequantized DCT coefficients in natural order.
+	private boolean[] isNb = new boolean[4]; // Is there a neighbor block for inverting the DC Prediction Process?
+	private int sbChromaWidth;
+	private int sbChromaHeight;
+	private int sbLumaWidth;
+	private int sbLumaHeight;
+	private int bChromaWidth;
+	private int bChromaHeight;
+	private int bLumaWidth;
+	private int bLumaHeight;
+	private int mbWidth;
+	private int mbHeight;
+	private byte[] zeroBytes;
+	private byte[] oneBytes;
+	private byte[][] oneBytesBytes;
+	private int pixelOffset;
+	private int pixelRange;
+	private int maximumPixelSize;
+	private int[] xBLength = new int[3];
+	private int[] yBLength = new int[3];
+	private int[] yBStart = new int[3];
+	private int[] yBEnd = new int[3];
+	private int externFrameCount;
+	private int internFrameCount;
+	private boolean restart;
+	
+	static {
+		int i;
+		
+		for(i = -CLIP_MIN; i < CLIP_MAX; i++) {
+			clip[i + CLIP_MIN] = (short) (i >= 0 ? i <= 255 ? i : 0xFF : 0);
+		}
+	}
+		
+	/**
+	 * Constructs an instance of <code>TheoraDecoder</code> with a
+	 * <code>VideoReader</code> object containing all necessary informations
+	 * about the media source.
+	 *
+	 * @param info     the <code>VideoReader</code> object containing all
+	 *      necessary informations about the media source
+	 */
+	TheoraDecoder(VideoReader info) {
+		super(info);
+		
+		nbs = info.blocks;
+		nsbs = info.superblocks;
+		nmbs = info.macroblocks;
+		sbChromaWidth = info.sbChromaWidth;
+		sbChromaHeight = info.sbChromaHeight;
+		sbLumaWidth = info.sbLumaWidth;
+		sbLumaHeight = info.sbLumaHeight;
+		mbWidth = info.mbWidth;
+		mbHeight = info.mbHeight;
+		qmat = info.qmat;
+		lflims = info.lflims;
+		maximumPixelSize = codedPictureWidth * codedPictureHeight;
+
+		chromaWidth = chromaFormat == CHROMA444 ? codedPictureWidth : codedPictureWidth >>> 1;
+		chromaHeight = chromaFormat != CHROMA420 ? codedPictureHeight : codedPictureHeight >>> 1;
+		
+		bChromaWidth = chromaWidth >>> 3;
+		bChromaHeight = chromaHeight >>> 3;
+		bLumaWidth = codedPictureWidth >>> 3;
+		bLumaHeight = codedPictureHeight >>> 3;
+		
+		nlsbs = sbLumaHeight * sbLumaWidth;
+		ncsbs = sbChromaHeight * sbChromaWidth;
+		
+		if (image == null) {
+			image = new short[3][];
+			image[0] = new short[maximumPixelSize];
+			image[1] = new short[chromaWidth * chromaHeight];
+			image[2] = new short[chromaWidth * chromaHeight];
+			ref  = new short[3][];
+			ref[0] = new short[maximumPixelSize];
+			ref[1] = new short[chromaWidth * chromaHeight];
+			ref[2] = new short[chromaWidth * chromaHeight];
+			goldRef = new short[3][];
+			goldRef[0] = new short[maximumPixelSize];
+			goldRef[1] = new short[chromaWidth * chromaHeight];
+			goldRef[2] = new short[chromaWidth * chromaHeight];
+		}
+		
+		zeroBytes = new byte[nsbs << 4];
+		oneBytes = new byte[nbs];
+		bCoded = new byte[nsbs][]; // Porting problem: Index can't be of type long (32 bit unsigned)
+	  	oneBytesBytes = new byte[nsbs][]; // Porting problem: Index can't be of type long (32 bit unsigned)
+	  	cbIndex = new int[nbs]; // Porting problem: Index can't be of type long (36 bit unsigned)
+		root = qcbIndex = new Node();
+		ncbIndex = new int[nbs]; // Porting problem: Index can't be of type long (36 bit unsigned)
+		cifbIndex = new int[nbs]; // Porting problem: Index can't be of type long (36 bit unsigned)
+		qiis = new byte[nsbs << 4]; // Porting problem: Index can't be of type long (36 bit unsigned)
+		tis = new byte[nsbs << 4]; // Porting problem: Index can't be of type long (36 bit unsigned)
+		coeffs = new short[nsbs << 4][64];
+		nCoeffs = new byte[nsbs << 4];
+		blockCoordinateX = new int[nsbs << 4];
+		blockCoordinateY = new int[nsbs << 4];
+		sbpCodedBits = new byte[nsbs]; // Porting problem: Should be long
+		sbfCodedBits = new byte[nsbs]; // Porting problem: Should be long
+		bits = new byte[nbs]; // Porting problem: Should be long
+
+		int blocksPerMakroblock = 4; // index 4 until 8 and 8 until 12 are equal to index 0 until 3
+		
+		if (chromaFormat == CHROMA420) {
+			blocksPerMakroblock = 5; // index 4 and 5 are equal
+		} else if (chromaFormat == CHROMA422) {
+			blocksPerMakroblock = 6; // index 4 and 5 are equal to index 6 and 7
+		}
+
+		mbMode = new byte[nmbs];
+		mbiToSbiLmbiMapping = new int[nmbs];
+		mVects = new byte[nmbs][blocksPerMakroblock][2];
+		biToMbiMapping = new int[nsbs << 4];
+		
+		int cpli, sbx, sby, sbi = 0, bi, sbibi, xSbEnd, ySbEnd, xBEnd, yBEnd, xEnd, yEnd;
+		int xSbLength[] = {sbLumaWidth, sbChromaWidth, sbChromaWidth};
+		int ySbLength[] = {sbLumaHeight, sbChromaHeight, sbChromaHeight};
+		
+		xBLength[0] = bLumaWidth;
+		xBLength[1] = xBLength[2] = bChromaWidth;
+		yBLength[0] = bLumaHeight;
+		yBLength[1] = yBLength[2] = bChromaHeight;
+		
+		int xSbRemainder;
+		int ySbRemainder;
+		int size;
+		int mbi;
+		int oneBytesIndex = 0;
+		
+		spipp = new int[nsbs];
+		pli = new int[nsbs];
+		planeWidthClip = new int[3][];
+		planeHeightClip = new int[3][];
+		
+		int[] planeWidthClipPointer = null;
+		int[] planeHeightClipPointer = null;
+		
+		int bx, by;
+
+		int mbWidth2 = mbWidth << 1;
+		int mbWidth4 = mbWidth << 2;
+		int ySbRemainderMinusOne;
+		int xSbRemainderMinusOne;
+		int ySbRemainderHalfMinusOne;
+		int ySbRemainder2;
+		int biShiftRightTwo;
+		
+		rasterOrderToCodedOrderMapping = new int[3][][];
+		
+		int[][] rasterOrderToCodedOrderMappingPointer;
+		
+		for (cpli = 0; cpli < 3; cpli++) {
+			xSbEnd = xSbLength[cpli];
+			ySbEnd = ySbLength[cpli];
+			xBEnd = xBLength[cpli];
+			yBEnd = yBLength[cpli];
+			xEnd = xBEnd << 3;
+			yEnd = yBEnd << 3;
+			rasterOrderToCodedOrderMappingPointer = rasterOrderToCodedOrderMapping[cpli] = new int[yBEnd][xBEnd];
+			if (cpli < 2) {
+				planeWidthClipPointer = planeWidthClip[cpli] = new int[xEnd + PLANE_CLIP_RANGE];
+				planeHeightClipPointer = planeHeightClip[cpli] = new int[yEnd + PLANE_CLIP_RANGE];
+				for (sbx = -PLANE_CLIP_MIN; sbx < xEnd + PLANE_CLIP_MAX; sbx++) {
+					planeWidthClipPointer[sbx + PLANE_CLIP_MIN] = sbx >= 0 ? sbx < xEnd ? sbx : xEnd - 1 : 0;
+				}
+				for (sby = -PLANE_CLIP_MIN; sby < yEnd + PLANE_CLIP_MAX; sby++) {
+					planeHeightClipPointer[sby + PLANE_CLIP_MIN] = sby >= 0 ? sby < yEnd ? sby : yEnd - 1 : 0;
+				}
+			} else {
+				planeWidthClip[2] = planeWidthClipPointer;
+				planeHeightClip[2] = planeHeightClipPointer;
+			}
+
+			for (sby = 0; sby < ySbEnd; sby++) {
+				if (sby == ySbEnd - 1) {
+					ySbRemainder = yBEnd & 0x3;
+					if (ySbRemainder == 0) {
+						ySbRemainder = 4;
+					}
+				} else {
+					ySbRemainder = 4;
+				}
+				ySbRemainderMinusOne = ySbRemainder - 1;
+				ySbRemainderHalfMinusOne = ySbRemainder / 2 - 1;
+				ySbRemainder2 = ySbRemainder << 1;
+				
+				for (sbx = 0; sbx < xSbEnd; sbx++) {
+					pli[sbi] = cpli;
+					if (sbx == xSbEnd - 1) {
+						xSbRemainder = xBEnd & 0x3;
+						if (xSbRemainder == 0) {
+							xSbRemainder = 4;
+						}
+					} else {
+						xSbRemainder = 4;
+					}
+					xSbRemainderMinusOne = xSbRemainder - 1;
+					size = xSbRemainder * ySbRemainder;
+
+					byte[] oneBytesBytesPointer = oneBytesBytes[sbi] = new byte[size];
+					
+					bCoded[sbi] = new byte[size];
+					
+					for (bi = 0; bi < size; bi++) {
+						oneBytesBytesPointer[bi] = 1;
+						oneBytes[oneBytesIndex++] = 1;
+						biShiftRightTwo = bi >>> 2;
+						sbibi = sbi << 4 | bi;
+						if (cpli == 0 || chromaFormat == CHROMA444) {
+							mbi = biToMbiMapping[sbibi] = biShiftRightTwo + sbx * ySbRemainder + sby * mbWidth2;
+							if (cpli == 0) {
+								mbiToSbiLmbiMapping[mbi] = sbi << 3 | biShiftRightTwo << 1 | ySbRemainder >>> 2;
+							}
+						} else {
+							if (chromaFormat == CHROMA422) {
+								biToMbiMapping[sbibi] = CHROMA_422_BI_TO_MBI_MAPPING[ySbRemainderHalfMinusOne][xSbRemainderMinusOne][bi] + sbx * ySbRemainder2 + sby * mbWidth2 - 1;
+							} else {
+								int value = CHROMA_420_BI_TO_MBI_MAPPING[ySbRemainderMinusOne][xSbRemainderMinusOne][bi];
+								
+								ySbRemainder2 = 8;
+
+								if (value < 0) {
+									value = -value;
+									if (ySbRemainder == 3) {
+										ySbRemainder2 = 4;
+									}
+									value += sbx * ySbRemainder2 + mbWidth2 + sby * mbWidth4 - 1;
+								} else {
+									if (ySbRemainder == 1) {
+										ySbRemainder2 = 4;
+									}
+									value += sbx * ySbRemainder2 + sby * mbWidth4 - 1;
+								}
+								biToMbiMapping[sbibi] = value;
+		 					}
+						}
+						cifbIndex[ncbs++] = sbibi;
+						qcbIndex = generate(sbibi, qcbIndex);
+						bx = sbx * 4 + SUPERBLOCK_X_BLOCKS_OFFSET[ySbRemainderMinusOne][xSbRemainderMinusOne][bi];
+						by = sby * 4 + SUPERBLOCK_Y_BLOCKS_OFFSET[ySbRemainderMinusOne][xSbRemainderMinusOne][bi];
+						rasterOrderToCodedOrderMappingPointer[by][bx] = sbibi;
+						blockCoordinateX[sbibi] = bx << 3;
+						blockCoordinateY[sbibi] = by << 3;
+					}
+					
+					if (cpli == 0) {
+						spipp[sbi] = sbi;
+					} else if (cpli == 1) {
+						spipp[sbi] = sbi - nlsbs;
+					} else {
+						spipp[sbi] = sbi - nlsbs - ncsbs;
+					}
+					sbi++;
+				}
+			}
+		}
+		
+		int qi; // The quantization index.
+		short r; // The edge detector response values.
+		short l; // The loop filter limit value.
+		short[] lflimPointer;
+
+		for (qi = 0; qi < 64; qi++) {
+			lflimPointer = lflim[qi];
+			l = lflims[qi];
+			for (r = 0; r < l; r++) {
+				lflimPointer[-r - l + FILTER_MIN] = (short) ( r - l);
+			 	lflimPointer[-r + FILTER_MIN] = (short) -r;
+			 	lflimPointer[ r + FILTER_MIN] = (short)  r;
+				lflimPointer[ r + l + FILTER_MIN] = (short) (-r + l);
+			}
+		}
+	}
+
+	/**
+	 * Decodes an still image.
+	 *
+	 * @exception IOException  if an I/O error occurs
+	 * @exception InterruptedIOException  if the decoding process is interrupted
+	 *      caused from malformed media data
+	 */
+	public synchronized void decodeStillImage() throws IOException {
+		skippedFrame = false;
+		try {
+			decode();
+			restart = true;
+		} catch (EndOfPacketException e) {
+			skippedFrame = true;
+		}
+	}
+
+	/**
+	 * Decodes an image.
+	 *
+	 * @exception IOException  if an I/O error occurs
+	 * @exception InterruptedIOException  if the decoding process is interrupted
+	 *      caused from malformed media data
+	 */
+	public synchronized void decodeImage() throws IOException {
+		skippedFrame = false;
+		try {
+			restart = false;
+			decode();
+		} catch (EndOfPacketException e) {
+			skippedFrame = true;
+		}
+	}
+	
+	void decode() throws IOException, EndOfPacketException {
+		
+		pixelOffset = maximumPixelSize;
+		
+		int pixelMax = -1;
+		
+		yBEnd[0] = yBEnd[1] = yBEnd[2] = 0;
+		yBStart[0] = yBLength[0];
+		yBStart[1] = yBStart[2] = yBLength[1];
+				
+		if (get1() != 0) {
+			throw new InterruptedIOException("No video packet");
+		}
+		
+		// 7.1 Frame Header Decode
+		
+		int moreQis; // A flag indicating there are more qi values to be decoded.
+		
+		int getBuffer = get(8);
+		
+		fType = getBuffer >>> 7;
+		qis[0] = getBuffer >>> 1 & 0x3F;
+		moreQis = getBuffer & 0x1;
+		
+		if (moreQis == 0) {
+			nqis = 1;
+		} else {
+			getBuffer = get(7);
+			
+			qis[1] = getBuffer >>> 1;
+			moreQis = getBuffer & 0x1;
+			if (moreQis == 0) {
+				nqis = 2;
+			} else {
+				qis[2] = get(6);
+				nqis = 3;
+			}
+		}
+		if (fType == INTRA_FRAME) {
+			pixelOffset = 0;
+			pixelRange = maximumPixelSize;
+			yBStart[0] = yBStart[1] = yBStart[2] = 0;
+			yBEnd[0] = yBLength[0];
+			yBEnd[1] = yBEnd[2] = yBLength[1];
+			if (get(3) != 0) {
+				throw new InterruptedIOException("Reserved values should be zero bytes");
+			}
+		}
+
+		// 7.3 Coded Block Flags Decode
+		// 7.4 Macro Block Coding Modes
+		
+		int nBits; // The length of a bit string to decode. // Porting problem: Should be long
+		int sbi; // The index of the current super block.
+		int bi; // The index of the current block in coded order.
+		int mbi = 0; // The index of the current macro block.
+		int lmbi = 0; // The index of the current luma macro block.
+		int psbi = -1; // The index of the previous super block.
+		int sbibi; // The index source of the index of the current super block and block.
+		
+		byte[] bCodedPointer;
+		byte[][] bCodedBuffer = bCoded;
+		byte[] mbModeBuffer = mbMode;
+		int[] cbIndexBuffer = cbIndex;
+		int bitCounter = 0; // Porting problem: Should be long
+		int biShiftRightTwo = 0;
+		byte mvx; // The horizontal component of the first whole-pixel motion vector.
+		byte mvy; // The vertical component of the first whole-pixel motion vector.
+		byte[][] mVectsPointer;
+		byte[] mVectsPointerArray;
+		byte mode;
+		
+		ncbs = 0;
+		nncbs = 0;
+		
+		qcbIndex = root;
+
+		if (fType == INTRA_FRAME) {
+			mbMode = oneBytes;
+			bCoded = oneBytesBytes;
+			cbIndex = cifbIndex;
+			ncbs = nbs;
+			qcbIndex = rebuildIntraCbIndexQueue(nbs, cbIndex, qcbIndex);
+		} else {
+			byte sbpCodedBit;
+			byte sbfCodedBit = 0;
+			int sbfCodedBitCounter = 0; // Porting problem: Should be long
+			int mScheme; // The mode coding scheme.
+			boolean[] lumaMakroBlockCoded = new boolean[4];
+			int lumaMakroBlockCodedValue;
+			
+			nBits = nsbs;
+			
+			runBitStringDecode(nBits, sbpCodedBits, HUFFMANCODETABLE7_7RSTART, HUFFMANCODETABLE7_7RBITS);
+			
+			for (sbi = nBits = 0; sbi < nsbs; sbi++) {
+				if (sbpCodedBits[sbi] == 0) {
+					nBits++;
+				}
+			}
+
+			if (nBits > 0) {
+
+				runBitStringDecode(nBits, sbfCodedBits, HUFFMANCODETABLE7_7RSTART, HUFFMANCODETABLE7_7RBITS);
+			
+				for (sbi = nBits = 0; sbi < nsbs; sbi++) {
+					if (sbpCodedBits[sbi] != 0) {
+						nBits += bCoded[sbi].length;
+					}
+				}
+			}
+
+			runBitStringDecode(nBits, bits, HUFFMANCODETABLE7_11RSTART, HUFFMANCODETABLE7_11RBITS);
+			
+			mScheme = get(3);
+			
+			if (mScheme == 0) {
+				for (mode = 0; mode < 8; mode++) {
+					// get(3) == The index of a Huffman code from Table 7.19, starting from 0
+					mAlphabet[get(3)] = mode;
+				}
+			} else if (mScheme != 7) {
+				System.arraycopy(HUFFMANCODETABLE7_14[mScheme], 0, mAlphabet, 0, mAlphabet.length);
+			}
+				
+			for (sbi = 0; sbi < nsbs; sbi++) {
+
+				bCodedPointer = bCoded[sbi];
+			
+				sbpCodedBit = sbpCodedBits[sbi];
+				
+				if (sbpCodedBit == 0) {
+					sbfCodedBit = sbfCodedBits[sbfCodedBitCounter++];
+				}
+	
+				lumaMakroBlockCoded[0] = false;
+				lumaMakroBlockCoded[1] = false;
+				lumaMakroBlockCoded[2] = false;
+				lumaMakroBlockCoded[3] = false;
+
+				for (bi = 0; bi < bCodedPointer.length; bi++) {
+
+					biShiftRightTwo = bi >>> 2;
+
+					lumaMakroBlockCodedValue = bCodedPointer[bi] = sbpCodedBit == 0 ? sbfCodedBit : bits[bitCounter++];
+					
+					if (lumaMakroBlockCodedValue != 0) {
+						sbibi = sbi << 4 | bi;
+						cbIndex[ncbs++] = sbibi;
+						qcbIndex = put(sbibi, qcbIndex);
+						lumaMakroBlockCoded[biShiftRightTwo] = true;
+					} else {
+						ncbIndex[nncbs++] = sbi << 4 | bi;
+					}
+				}
+				if (sbi < nlsbs) {
+					int lmbiEnd = biShiftRightTwo + 1;
+
+					for (lmbi = 0; lmbi < lmbiEnd; lmbi++, mbi++) {
+						mbMode[mbi] = lumaMakroBlockCoded[lmbi] ? mScheme != 7 ? mAlphabet[getHuffcodeTableIndex(mAlphabet.length)] : (byte) get(3) : INTER_NOMV;
+					}
+				}
+			}
+		
+			// 7.5 Motion Vectors
+			// 7.5.2 Macro Block Motion Vector Decode
+		
+			byte last1x = 0; // The last motion vector x value.
+			byte last1y = 0; // The last motion vector y value.
+			byte last2x = 0; // The last motion vector x value.
+			byte last2y = 0; // The last motion vector y value.
+			byte[] mVectsChroma1PointerArray;
+			byte[] mVectsChroma2PointerArray;
+			int mvMode = get1(); // The motion vector decoding method.
+			int mbModePointerValue;
+			int bri; // block index in raster order.
+			byte[] orderMappingPointer;
+			int sum, sumABx, sumABy, sumCDx, sumCDy;
+			byte mbModeValue = 0;
+			int mbiToSbiLmbiMappingValue;
+			int lmbiShiftLeftTwo;
+			
+			bCodedPointer = null;
+		
+			if (ncbs > 0) {
+				for (mbi = 0; mbi < mVects.length; mbi++) {
+					mbiToSbiLmbiMappingValue = mbiToSbiLmbiMapping[mbi];
+					sbi = mbiToSbiLmbiMappingValue >>> 3;
+					lmbi = mbiToSbiLmbiMappingValue >>> 1 & 0x3;
+					lmbiShiftLeftTwo = lmbi << 2;
+					mbModeValue = mbMode[mbi];
+					mVectsPointer = mVects[mbi];
+					orderMappingPointer = CODING_ORDER_TO_BLOCK_RASTER_ORDER[mbiToSbiLmbiMappingValue & 0x1][lmbi];
+					if (psbi != sbi) {
+						bCodedPointer = bCoded[sbi];
+						psbi = sbi;
+					}
+					mVectsPointerArray = mVectsPointer[0];
+					mVectsPointerArray[0] = mVectsPointerArray[1] = 0;
+			 		if (mbModeValue == INTER_MV_FOUR) {
+						last2x = last1x;
+						last2y = last1y;
+						sumABx = sumABy = sumCDx = sumCDy = 0;
+						for (bi = 0; bi < 4; bi++) {
+							bri = orderMappingPointer[bi];
+						
+							mVectsPointerArray = mVectsPointer[bri];
+						
+							if (bCodedPointer[lmbiShiftLeftTwo | bri] != 0) {
+								motionVectorDecode(mVectsPointerArray, mvMode);
+			 					last1x = mVectsPointerArray[0];
+								last1y = mVectsPointerArray[1];
+								if (bri < 2) {
+									sumABx += last1x;
+									sumABy += last1y;
+								} else {
+									sumCDx += last1x;
+									sumCDy += last1y;
+								}
+			 				} else {
+								mVectsPointerArray[0] = mVectsPointerArray[1] = 0;
+							}
+						}
+					
+						mVectsChroma1PointerArray = mVectsPointer[4];
+					
+						if (chromaFormat == CHROMA420) {
+							sum = sumABx + sumCDx;
+							mVectsChroma1PointerArray[0] = (byte) ((sum + (sum < 0 ? -2 : 2)) / 4);
+
+							sum = sumABy + sumCDy;
+							mVectsChroma1PointerArray[1] = (byte) ((sum + (sum < 0 ? -2 : 2)) / 4);
+						} else if (chromaFormat == CHROMA422) {
+							mVectsChroma2PointerArray = mVectsPointer[5];
+				
+							mVectsChroma1PointerArray[0] = (byte) ((sumABx + (sumABx < 0 ? -1 : 1)) / 2);
+							mVectsChroma2PointerArray[0] = (byte) ((sumCDx + (sumCDx < 0 ? -1 : 1)) / 2);
+							mVectsChroma1PointerArray[1] = (byte) ((sumABy + (sumABy < 0 ? -1 : 1)) / 2);
+							mVectsChroma2PointerArray[1] = (byte) ((sumCDy + (sumCDy < 0 ? -1 : 1)) / 2);
+						}
+					} else if (mbModeValue == INTER_GOLDEN_MV) {
+						motionVectorDecode(mVectsPointerArray, mvMode);
+					} else if (mbModeValue == INTER_MV_LAST2) {
+						mVectsPointerArray[0] = last2x;
+						mVectsPointerArray[1] = last2y;
+						last2x = last1x;
+						last2y = last1y;
+						last1x = mVectsPointerArray[0];
+						last1y = mVectsPointerArray[1];
+					} else if (mbModeValue == INTER_MV_LAST) {
+						mVectsPointerArray[0] = last1x;
+						mVectsPointerArray[1] = last1y;
+					} else if (mbModeValue == INTER_MV) {
+						motionVectorDecode(mVectsPointerArray, mvMode);
+						last2x = last1x;
+						last2y = last1y;
+						last1x = mVectsPointerArray[0];
+						last1y = mVectsPointerArray[1];
+					}
+					if (mbModeValue != INTER_MV_FOUR) {
+						mvx = mVectsPointerArray[0];
+						mvy = mVectsPointerArray[1];
+						for (bi = 1; bi < mVectsPointer.length; bi++) {
+							mVectsPointerArray = mVectsPointer[bi];
+							mVectsPointerArray[0] = mvx;
+							mVectsPointerArray[1] = mvy;
+						}
+					}
+				}
+			}
+		}
+		
+		// 7.6 Block-Level qi Decode
+		
+		if(ncbs > 0) {
+			int qii; // The index of qi value in the list of qi values defined for this frame.
+			int cbi; // The index of the current block in the coded block list.
+			int qiiPlusOne;
+		
+			nBits = ncbs;
+			System.arraycopy(zeroBytes, 0, qiis, 0, qiis.length);
+		
+			if (nqis > 1 && ncbs > 0) {
+			
+				runBitStringDecode(nBits, bits, HUFFMANCODETABLE7_7RSTART, HUFFMANCODETABLE7_7RBITS);
+			
+				for (qii = 0; ; qii++) {
+					qiiPlusOne = qii + 1;
+					for (cbi = bitCounter = nBits = 0; cbi < ncbs; cbi++) {
+						sbibi = cbIndex[cbi];
+						if (qiis[sbibi] == qii) {
+							qiis[sbibi] += bits[bitCounter++];
+							if (qiis[sbibi] == qiiPlusOne) {
+								nBits++;
+							}
+						}
+					}
+					if (qii < nqis - 2) {
+						runBitStringDecode(nBits, bits, HUFFMANCODETABLE7_7RSTART, HUFFMANCODETABLE7_7RBITS);
+					} else {
+						break;
+					}
+				}
+			}
+		
+      		// 7.7 DCT Coefficients
+			// 7.7.3 DCT Coefficient Decode
+		
+			int token; // No The current token being decoded.
+			int hg; // No The current Huffman table group.
+			int ti = 0; // The current token index.
+			int htil = 0; // The index of the current Huffman table to use for the luma plane within a group.
+			int htic = 0; // The  index of the current Huffman table to use for the chroma planes ithin a group.
+			int hti; // The index of the current Huffman table to use.
+			short[] coeffsPointer = null;
+			int psbibi = -1;
+		
+			System.arraycopy(zeroBytes, 0, tis, 0, tis.length);
+		
+			eobs = 0;
+		
+			for (; ti < 64 ; ti++) {
+				qcbIndex = root;
+		
+				if (ti == 0 || ti == 1) {
+					getBuffer = get(8);
+					htil = getBuffer >>> 4;
+					htic = getBuffer & 0xF;
+				}
+				
+				while (traversable(qcbIndex)) {
+			
+					qcbIndex = qcbIndex.next;
+				
+					sbibi = qcbIndex.index;
+					
+					if (psbibi != sbibi) {
+						coeffsPointer = coeffs[sbibi];
+						psbibi = sbibi;
+					}
+				
+					if (tis[sbibi] == ti) {
+						nCoeffs[sbibi] = (byte) ti;
+					
+						if (eobs != 0) {
+							coeffsPointer[ti] = 0;
+							tis[sbibi] = 64;
+							remove(qcbIndex);
+							eobs--;
+						} else {
+							hg = HUFFMAN_GROUP_TABLE7_42[ti];
+							hti = pli[sbibi >>> 4] == 0 ? hg << 4 | htil : hg << 4 | htic;
+						
+							token = getCodeWord(hti);
+						
+							if (token < 7) {
+								eobs = token < 3 ? token : get(TOKEN_TABLE7_33[0][token]) + TOKEN_TABLE7_33[1][token];
+								coeffsPointer[ti] = 0;
+								nCoeffs[sbibi] = tis[sbibi];
+								tis[sbibi] = 64;
+								remove(qcbIndex);
+							} else {
+								coefficientTokenDecode(coeffsPointer, nCoeffs, tis, token, sbibi, ti);
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		// 7.8 Undoing DC Prediction
+		// 7.8.1 Computing the DC Predictor
+		// 7.8.2 Inverting the DC Prediction Process
+		// 7.9 Reconstruction
+		
+		int ci; // The DCT coefficient index in natural order
+				// in opposite to the DCT coefficient index in zig-zag order
+				// == {int zzi = ZIG_ZAG_SCAN[ci];}.
+		int dc = 0; // The actual DC value for the current block.
+		int dcPred = 0; // The predicted DC value for the current block.
+		int rfi; // The index of the reference frame indicated by the coding mode for macro block mbi.
+		int cpli = 0; // The current plane index.
+		int nbii; // The index of the index of neighbor blocks.
+		int nbiiCounter; // The index of the index of neighbor blocks counter.
+		int bj; // The index of a neighboring block in oded order.
+		int sbj; // The index of a neighboring superblock in oded order.
+		//int pdiv; // The valud to divide the weighted sum by.
+		short[] weightsDivisorTableOuterPointer;
+		int table47index;
+		//byte mvx; // The horizontal component of the first whole-pixel motion vector.
+		//byte mvy; // The vertical component of the first whole-pixel motion vector.
+		byte mvx2 = mvx = 0; // The horizontal component of the second whole-pixel motion vector.
+		byte mvy2 = mvy = 0; // The vertical component of the second whole-pixel motion vector.
+		int qti; // A quantization type index. See Table 3.1.
+		int qi0 = qis[0]; // The quantization index of the DC coefficient.
+		short[] refp = null; // A RPH/RPW array containing the contents of the current plane of the reference frame.
+		int refpi; // The pixel index of the reference plane pointer.
+		short[] imp = null; // A RPH/RPW array containing the contents of the current plane of the current frame.
+		int impi; // The pixel index of the current image plane pointer.
+		int[] clipW = null;
+		int[] clipH = null;
+		int[] rasterOrderToCodedOrderMappingInnerPointer;
+		int[][] rasterOrderToCodedOrderMappingOuterPointer;
+		int pbx; // The horizontal pixel index of the lower left edge of the current block.
+		int pby; // The vertical pixel index of the lower left edge of the current block.
+		int bx; // The horizontal block index of the current block.
+		int by; // The vertical block index of the current block.
+		int nbx; // The horizontal neighbor block index of the current block.
+		int nby; // The vertical neighbor block index of the current block.
+		int wcps = 0; // The width of the current plane in pixels.
+		int hcps = 0; // The height of the current plane in pixels.
+		int wcbs = 0; // The width of the current plane in blocks.
+		int hcbs; // The height of the current plane in blocks.
+		int sbjbj; // The index source of the index of the neighbor super block and block.
+		boolean sparseDc;
+		byte[] chromaSelectionPointer;
+		int nc;
+		int pbyShift = 0;
+		
+		for (; cpli < 3 && ncbs > 0; cpli++) {
+			System.arraycopy(ZERO_SHORTS, 0, lastDc, 0, 3);
+			clipW = planeWidthClip[cpli];
+			clipH = planeHeightClip[cpli];
+			wcps = clipW.length - PLANE_CLIP_RANGE;
+			hcps = clipH.length - PLANE_CLIP_RANGE;
+			wcbs = wcps >>> 3;
+			hcbs = hcps >>> 3;
+			imp = image[cpli];
+			rasterOrderToCodedOrderMappingOuterPointer = rasterOrderToCodedOrderMapping[cpli];
+			if (cpli != 0 && chromaFormat == CHROMA420) {
+				pbyShift = 1;
+			}
+			for (by = 0; by < hcbs; by++) {
+				pby = by << 3;
+				rasterOrderToCodedOrderMappingInnerPointer = rasterOrderToCodedOrderMappingOuterPointer[by];
+				chromaSelectionPointer = CHROMA_422_MOTIONVECTOR_SELECTION[by == hcbs - 1 && hcbs % 4 != 0 ? 0 : 1];
+
+				for (bx = 0; bx < wcbs; bx++) {
+					pbx = bx << 3;
+						
+					sbibi = rasterOrderToCodedOrderMappingInnerPointer[bx];
+					
+					sbi = sbibi >>> 4;
+					bi = sbibi & 0xF;
+					
+					mbi = biToMbiMapping[sbibi];
+
+					if (bCoded[sbi][bi] != 0) {
+						
+						mode = mbMode[mbi];
+
+						isNb[0] = bx != 0 ? true : false;
+						isNb[1] = bx != 0 && by != 0 ? true : false;
+						isNb[2] = by != 0 ? true : false;
+						isNb[3] = bx != wcbs - 1 && by != 0 ? true : false;
+					
+						rfi = CODE_MODE_TABLE7_46[mode];
+						
+						for (nbii = table47index = nbiiCounter = 0; nbii < 4; nbii++) {
+							if (isNb[nbii]) {
+								nbx = nbii == 0 ? bx - 1 : bx + nbii - 2;
+								nby = nbii == 0 ? by : by - 1;
+								sbjbj = rasterOrderToCodedOrderMappingOuterPointer[nby][nbx];
+					
+								sbj = sbjbj >>> 4;
+								bj = sbjbj & 0xF;
+							
+								if (bCoded[sbj][bj] != 0 && rfi == CODE_MODE_TABLE7_46[mbMode[biToMbiMapping[sbjbj]]]) {
+									table47index |= 1 << nbii;
+									coeffsValues[nbiiCounter++] = coeffs[sbjbj][0];
+								}
+							}
+						}
+						if (table47index == 0) {
+							coeffs[sbibi][0] += lastDc[rfi];
+						} else {
+							weightsDivisorTableOuterPointer = DCPREDICTORS_WEIGHTS_AND_DIVISORS_TABLE7_47[table47index];
+							dcPred = weightsDivisorTableOuterPointer[0] * coeffsValues[0];
+							if (nbiiCounter > 1) {
+								for (nbii = 1; nbii < nbiiCounter; nbii++) {
+									dcPred += weightsDivisorTableOuterPointer[nbii] * coeffsValues[nbii];
+								}
+								dcPred /= weightsDivisorTableOuterPointer[4];
+								if ((table47index & 0x7) == 7) {
+									if (dcPred - coeffsValues[2] > 128 || dcPred - coeffsValues[2] < -128) {
+										dcPred = coeffsValues[2];
+									} else if (dcPred - coeffsValues[0] > 128 || dcPred - coeffsValues[0] < -128) {
+										dcPred = coeffsValues[0];
+									} else if (dcPred - coeffsValues[1] > 128 || dcPred - coeffsValues[1] < -128) {
+										dcPred = coeffsValues[1];
+									}
+								}
+							}
+							coeffs[sbibi][0] += dcPred;
+						}
+						lastDc[rfi] = coeffs[sbibi][0];
+					
+						// 7.9.4 The Complete Reconstruction Algorithm
+					
+						qti = mode == INTRA ? 0 : 1;
+						
+						if (rfi != 0) {// Table 7.75: Reference Planes and Sizes for Each rfi and pli
+							if (rfi == 1) {
+								refp = ref[cpli];
+							} else {
+								refp = goldRef[cpli];
+							}
+							if (mode != INTER_NOMV && mode != INTER_GOLDEN_NOMV) {
+								mVectsPointer = mVects[mbi];
+				
+								if (cpli == 0 || chromaFormat == CHROMA444) {
+									mVectsPointerArray = mVectsPointer[bi & 0x3];
+								} else if (chromaFormat == CHROMA422) {
+									mVectsPointerArray = mVectsPointer[chromaSelectionPointer[bi]];
+								} else {
+									mVectsPointerArray = mVectsPointer[4];
+								}
+				
+								int xChromaDecimation = (chromaFormat & 1) == 0 && cpli != 0 ? 1 : 0;
+
+								int yChromaDecimation = (chromaFormat & 2) == 0 && cpli != 0 ? 1 : 0;
+				
+								mvx = MOTIONVECTOR_MAPPING_BASE[xChromaDecimation][mVectsPointerArray[0] + 31];
+								mvy = MOTIONVECTOR_MAPPING_BASE[yChromaDecimation][mVectsPointerArray[1] + 31];
+								mvx2 = MOTIONVECTOR_MAPPING_DIFF[xChromaDecimation][mVectsPointerArray[0] + 31];
+								mvy2 = MOTIONVECTOR_MAPPING_DIFF[yChromaDecimation][mVectsPointerArray[1] + 31];
+							} else {
+								mvx = 0;
+								mvy = 0;
+								mvx2 = 0;
+								mvy2 = 0;
+							}
+						}
+			
+						short[] qm0 = qmat[qti][cpli][qi0];
+						short[] qm = qmat[qti][cpli][qis[qiis[sbibi]]];
+
+						nc = nCoeffs[sbibi];
+				
+						sparseDc = false;
+
+						if (nc < 2) {
+							dc = (short) (coeffs[sbibi][0] * qm0[0] + 15 >> 5);
+							if (dc == 0) {
+								sparseDc = true;
+							} else {
+								for (ci = 0; ci < 64; ci++) {
+									dqc[ci] = dc;
+								}
+							}
+						} else {
+							dequantization(qm0, qm, coeffs[sbibi], nc);
+							if (nc <= 3) {
+								inverseDCT2D3();
+							} else if (nc <= 6) {
+								inverseDCT2D6();
+							} else if (nc <= 10) {
+								inverseDCT2D10();
+							} else {
+								inverseDCT2D(ZIG_ZAG_TO_NATURAL_ORDER_ROW_MAPPING[nc - 1]);
+							}
+						}
+						if (rfi == 0) {
+							intraPredictor(imp, clipW, pbx, pby, sparseDc);
+						} else {
+							if (mvx2 != 0 || mvy2 != 0) {
+								mvx2 += mvx;
+								mvy2 += mvy;
+								halfPixelPredictor(imp, refp, clipW, clipH, mvx, mvy, mvx2, mvy2, pbx, pby, sparseDc);
+							} else {
+								if (mvx != 0 || mvy != 0) {
+									wholePixelPredictor(imp, refp, clipW, clipH, mvx, mvy, pbx, pby, sparseDc);
+								} else {
+									wholePixelPredictor(imp, refp, clipW, clipH, pbx, pby, sparseDc);
+								}
+							}
+						}
+						impi = (pby << pbyShift) * codedPictureWidth;
+						
+						if (impi > pixelMax) {
+							pixelMax = impi;
+							pixelRange = pixelMax + 8 * codedPictureWidth;
+						}
+						if (impi < pixelOffset) {
+							pixelOffset = impi;
+							pixelRange = pixelMax + 8 * codedPictureWidth;
+						}
+					}
+					int byPlusOne = by + 1;
+					
+					if (byPlusOne > yBEnd[cpli]) {
+						yBEnd[cpli] = byPlusOne;
+					}
+					if (by < yBStart[cpli]) {
+						yBStart[cpli] = by;
+					}
+				}
+			}
+		}
+
+		short[][] swap; // swap image pointer.
+		int ppli = -1; // The last color plane index.
+		int pbi = 0; // The index of the current pointed block in the non coded or coded block list.
+		int pbs = ncbs; // An NBS-element array of pointed block indices // Porting problem: Should be long[]
+		int[] pbIndex = cbIndex; // An NBS-element array of pointed block indices // Porting problem: Should be long[]
+
+		if (ncbs > nncbs) {
+			swap = image;
+			image = ref;
+			ref = swap;
+			pbs = nncbs;
+			pbIndex = ncbIndex;
+		}
+
+		for (psbi = -1; pbi < pbs; pbi++) {
+			
+			sbibi = pbIndex[pbi];
+			
+			sbi = sbibi >>> 4;
+			
+			if (psbi != sbi) {
+				cpli = pli[sbi];
+				if (ppli != cpli) {
+					ppli = cpli;
+					imp = image[cpli];
+					refp = ref[cpli];
+					clipW = planeWidthClip[cpli];
+					clipH = planeHeightClip[cpli];
+					wcps = clipW.length - PLANE_CLIP_RANGE;
+					hcps = clipH.length - PLANE_CLIP_RANGE;
+				}
+				psbi = sbi;
+			}
+			
+			impi = blockCoordinateY[sbibi] * wcps + blockCoordinateX[sbibi];
+			System.arraycopy(imp, impi        , refp, impi, 8);
+			System.arraycopy(imp, impi += wcps, refp, impi, 8);
+			System.arraycopy(imp, impi += wcps, refp, impi, 8);
+			System.arraycopy(imp, impi += wcps, refp, impi, 8);
+			System.arraycopy(imp, impi += wcps, refp, impi, 8);
+			System.arraycopy(imp, impi += wcps, refp, impi, 8);
+			System.arraycopy(imp, impi += wcps, refp, impi, 8);
+			System.arraycopy(imp, impi += wcps, refp, impi, 8);
+		}
+		
+		// 7.10 Loop Filtering
+		// 7.10.3 Complete Loop Filter
+		
+		int fx; // The horizontal pixel index of the lower-left corner of the area to be filtered.
+		int fy; // The vertical pixel index of the lower-left corner of the area to be filtered.
+		int l = lflims[qi0]; // The loop filter limit value.
+		
+		if (l != 0) {
+			short[] lflimPointer = lflim[qi0];
+			int[] rasterOrderToCodedOrderMappingYPlusOne = null;
+			int bxPlusOne;
+			int byPlusOne;
+
+			for (cpli = 0; cpli < 3; cpli++) {
+				clipW = planeWidthClip[cpli];
+				clipH = planeHeightClip[cpli];
+				wcps = clipW.length - PLANE_CLIP_RANGE;
+				hcps = clipH.length - PLANE_CLIP_RANGE;
+				wcbs = wcps >>> 3;
+				hcbs = hcps >>> 3;
+				refp = ref[cpli];
+				rasterOrderToCodedOrderMappingOuterPointer = rasterOrderToCodedOrderMapping[cpli];
+
+				for (by = yBStart[cpli]; by < yBEnd[cpli]; by++) {
+					pby = by << 3;
+
+					rasterOrderToCodedOrderMappingInnerPointer = rasterOrderToCodedOrderMappingOuterPointer[by];
+					byPlusOne = by + 1;
+
+					if (byPlusOne < hcbs) {
+						rasterOrderToCodedOrderMappingYPlusOne = rasterOrderToCodedOrderMappingOuterPointer[byPlusOne];
+					}
+					for (bx = 0; bx < wcbs; bx++) {
+						pbx = bx << 3;
+
+						sbibi = rasterOrderToCodedOrderMappingInnerPointer[bx];
+					
+						sbi = sbibi >>> 4;
+						bi = sbibi & 0xF;
+
+						if(bCoded[sbi][bi] == 0) {
+							continue;
+						}
+					
+						bxPlusOne = bx + 1;
+						if (bx > 0) {
+							fx = pbx - 2;
+							fy = pby;
+							horizontalFilter(refp, lflimPointer, fx, fy, wcps);
+						}
+						if (by > 0) {
+							fx = pbx;
+							fy = pby - 2;
+							verticalFilter(refp, lflimPointer, fx, fy, wcps);
+						}
+						if (bxPlusOne < wcbs) {
+							sbjbj = rasterOrderToCodedOrderMappingInnerPointer[bxPlusOne];
+					
+							sbj = sbjbj >>> 4;
+							bj = sbjbj & 0xF;
+
+							if(bCoded[sbj][bj] == 0) {
+								fx = pbx + 6;
+								fy = pby;
+								horizontalFilter(refp, lflimPointer, fx, fy, wcps);
+							}
+						}
+						if (byPlusOne < hcbs) {
+							sbjbj = rasterOrderToCodedOrderMappingYPlusOne[bx];
+					
+							sbj = sbjbj >>> 4;
+							bj = sbjbj & 0xF;
+
+							if (bCoded[sbj][bj] == 0) {
+								fx = pbx;
+								fy = pby + 6;
+								verticalFilter(refp, lflimPointer, fx, fy, wcps);
+							}
+						}
+					}
+				}
+			}
+		}
+
+		if (fType == INTRA_FRAME) {
+			System.arraycopy(ref[0], 0, goldRef[0], 0, ref[0].length);
+			System.arraycopy(ref[1], 0, goldRef[1], 0, ref[1].length);
+			System.arraycopy(ref[2], 0, goldRef[2], 0, ref[2].length);
+			
+			mbMode = mbModeBuffer;
+			bCoded = bCodedBuffer;
+			cbIndex = cbIndexBuffer;
+		}
+		internFrameCount++;
+		internFrameCount %= maximumPixelSize;
+	}
+	
+	private void coefficientTokenDecode(short[] coeffs, byte[] nCoeffs, byte[] tis, int token, int bi, int ti) throws IOException, EndOfPacketException {
+		int sign; // A flag indicating the sign of the current coefficient.
+		int mag; // The magnitude of the current coefficient.
+		int rlen; // The length of the current ZERO_BYTES run.
+		int extraBits = TOKEN_TABLE7_33[0][token];
+		int offset = TOKEN_TABLE7_33[1][token];
+		int tokenRange = TOKEN_TABLE7_33[2][token];
+		int coeffsValue;
+		int coeffsIndex;
+		int getBuffer;
+		byte tisbi;
+		
+		if (tokenRange == 1) {
+			rlen = get(extraBits);
+			coeffsIndex = NATURAL_ORDER_SCAN[rlen + ti];
+			coeffsValue = 0;
+		} else if (tokenRange == 2) {
+			coeffsIndex = ti;
+			coeffsValue = offset;
+			
+			if (extraBits >= 1) {
+				sign = get1();
+				if (extraBits > 1) {
+					coeffsValue += get(extraBits - 1);
+				}
+				if (sign != 0) {
+					coeffsValue = -coeffsValue;
+				}
+			}
+		} else if (tokenRange == 3) {
+			coeffsValue = 1;
+			coeffsIndex = ti + offset;
+			sign = get1();
+			if (extraBits > 1) {
+				coeffsIndex += get(extraBits - 1);
+			}
+			if (sign != 0) {
+				coeffsValue = -coeffsValue;
+			}
+			coeffsIndex = NATURAL_ORDER_SCAN[coeffsIndex];
+		} else {
+			getBuffer = get(2);
+			sign = getBuffer >>> 1;
+			mag = (getBuffer & 0x1) + 2;
+			
+			if (offset == 0) {
+				coeffsIndex = NATURAL_ORDER_SCAN[ti + 1];
+			} else {
+				coeffsIndex = NATURAL_ORDER_SCAN[ti + get1() + 2];
+			}
+			coeffsValue = mag;
+			if (sign != 0) {
+				coeffsValue = -coeffsValue;
+			}
+		}
+		
+		rlen = coeffsIndex - ti;
+		
+		if (rlen > 0) {
+			System.arraycopy(ZERO_SHORTS, 0, coeffs, ti, rlen);
+		}
+		tisbi = tis[bi];
+		if ((tisbi += rlen + 1) >= 64) {
+			if (tisbi > 64) {
+				tisbi = 64;
+			}
+			qcbIndex = remove(qcbIndex);
+		}
+		tis[bi] = tisbi;
+		coeffs[coeffsIndex] = (short) coeffsValue;
+		if (tokenRange != 1) {
+			nCoeffs[bi] = tisbi;
+		}
+	}
+	
+	private void runBitStringDecode(int nBits, byte[] bits, byte[] huffmanCodeTableRstart, byte[] huffmanCodeTableRbits) throws IOException, EndOfPacketException {
+		
+		// 7.2 Run-Length Encoded Bit Strings
+		// 7.2.1 Long-Run Bit String Decode
+		// 7.2.2 Short-Run Bit String Decode
+		
+		int len = 0; // The number of bits decoded so far. // Porting problem: Should be long
+		int bit; // The value associated with the current run.
+		int rlen; // The length of the current run.
+		int rbits; // The number of extra bits needed to decode the run length.
+		//int rstart; // The start of the possible run-length values for a given Huffman code.
+		//int roffs; // The offset from RSTART of the runlength.
+		int index;
+		
+		if (len == nBits) {
+			return;
+		}
+
+		bit = get1();
+		
+		for (; ; ) {
+			index = getHuffcodeTableIndex(huffmanCodeTableRstart.length);
+			rbits = huffmanCodeTableRbits[index];
+			rlen = huffmanCodeTableRstart[index] + get(rbits);
+						
+			if (bit == 1) {
+				System.arraycopy(oneBytes, 0, bits, len, rlen);
+			} else {
+				System.arraycopy(zeroBytes, 0, bits, len, rlen);
+			}
+
+			len += rlen;
+			if (len >= nBits) {
+				return;
+			}
+			if (rlen == 4129) {
+				bit = get1();
+			} else {
+				bit ^= 1;
+			}
+		}
+	}
+	
+	private int getHuffcodeTableIndex(int length) throws IOException, EndOfPacketException {
+		int lengthMinusOne = length - 1;
+		int ilog = 0;
+		int i;
+		
+		for (i = 0; i < length; i++) {
+			if (get1() == 1) {
+				if (++ilog == lengthMinusOne) {
+					return ilog;
+				}
+			} else {
+				break;
+			}
+		}
+		return ilog;
+	}
+	
+	private void motionVectorDecode(byte[] mv, int mvMode) throws IOException, EndOfPacketException {
+		
+		// 7.5.1 Motion Vector Decode
+		
+		// int mvSign; // The sign of the motion vector component just decoded.
+		int bitPattern;
+		int mvx, mvy;
+		
+		if (mvMode == 0) {
+			mvx = HUFFMANCODETABLE7_23[0][get(3)];
+			if (mvx < 0) {
+				mvx = -mvx;
+				if (mvx == 2) {
+					bitPattern = get1();
+				} else {
+					bitPattern = get(mvx);
+				}
+				mvx = HUFFMANCODETABLE7_23[mvx][bitPattern];
+			}
+			mvx -= 31;
+			
+			mvy = HUFFMANCODETABLE7_23[0][get(3)];
+			if (mvy < 0) {
+				mvy = -mvy;
+				if (mvy == 2) {
+					bitPattern = get1();
+				} else {
+					bitPattern = get(mvy);
+				}
+				mvy = HUFFMANCODETABLE7_23[mvy][bitPattern];
+			}
+			mvy -= 31;
+			
+		} else {
+			mvx = get(5);
+			if (get1() == 1) {
+				mvx = -mvx;
+			}
+			mvy = get(5);
+			if (get1() == 1) {
+				mvy = -mvy;
+			}
+		}
+
+		mv[0] = (byte) mvx;
+		mv[1] = (byte) mvy;
+	}
+
+
+	private void intraPredictor(short[] image, int[] clipW, int pbx, int pby, boolean sparseDc) {
+
+		// 7.9.1 Predictors
+
+		int rpw = clipW.length - PLANE_CLIP_RANGE; // The width of the current plane of the reference frame in pixels.
+		int offset = pby * rpw + pbx;
+		
+		if (sparseDc) {
+			System.arraycopy(ONE_HUNDRED_TWENTYEIGHT_INTS, 0, image, offset       , 8);
+			System.arraycopy(ONE_HUNDRED_TWENTYEIGHT_INTS, 0, image, offset += rpw, 8);
+			System.arraycopy(ONE_HUNDRED_TWENTYEIGHT_INTS, 0, image, offset += rpw, 8);
+			System.arraycopy(ONE_HUNDRED_TWENTYEIGHT_INTS, 0, image, offset += rpw, 8);
+			System.arraycopy(ONE_HUNDRED_TWENTYEIGHT_INTS, 0, image, offset += rpw, 8);
+			System.arraycopy(ONE_HUNDRED_TWENTYEIGHT_INTS, 0, image, offset += rpw, 8);
+			System.arraycopy(ONE_HUNDRED_TWENTYEIGHT_INTS, 0, image, offset += rpw, 8);
+			System.arraycopy(ONE_HUNDRED_TWENTYEIGHT_INTS, 0, image, offset += rpw, 8);
+			return;
+		}
+		int j = 0;
+		int clipMinPlus128 = 128 + CLIP_MIN;
+
+		for (int i = 0; i < 8; i++) {
+			image[offset    ] = clip[dqc[j++] + clipMinPlus128];
+			image[offset | 1] = clip[dqc[j++] + clipMinPlus128];
+			image[offset | 2] = clip[dqc[j++] + clipMinPlus128];
+			image[offset | 3] = clip[dqc[j++] + clipMinPlus128];
+			image[offset | 4] = clip[dqc[j++] + clipMinPlus128];
+			image[offset | 5] = clip[dqc[j++] + clipMinPlus128];
+			image[offset | 6] = clip[dqc[j++] + clipMinPlus128];
+			image[offset | 7] = clip[dqc[j++] + clipMinPlus128];
+			offset += rpw;
+		}
+	}
+	
+	private void wholePixelPredictor(short[] image, short[] refp, int[] clipW, int[] clipH, int pbx, int pby, boolean sparseDc) {
+				
+		// 7.9.1 Predictors
+
+		int rpw = clipW.length - PLANE_CLIP_RANGE; // The width of the current plane of the reference frame in pixels.
+		int offset = pby * rpw + pbx;
+		
+		if (sparseDc) {
+			System.arraycopy(refp, offset       , image, offset, 8);
+			System.arraycopy(refp, offset += rpw, image, offset, 8);
+			System.arraycopy(refp, offset += rpw, image, offset, 8);
+			System.arraycopy(refp, offset += rpw, image, offset, 8);
+			System.arraycopy(refp, offset += rpw, image, offset, 8);
+			System.arraycopy(refp, offset += rpw, image, offset, 8);
+			System.arraycopy(refp, offset += rpw, image, offset, 8);
+			System.arraycopy(refp, offset += rpw, image, offset, 8);
+			return;
+		}
+		int j = 0;
+		
+		for (int i = 0; i < 8; i++) {
+			image[offset    ] = clip[dqc[j++] + refp[offset    ] + CLIP_MIN];
+			image[offset | 1] = clip[dqc[j++] + refp[offset | 1] + CLIP_MIN];
+			image[offset | 2] = clip[dqc[j++] + refp[offset | 2] + CLIP_MIN];
+			image[offset | 3] = clip[dqc[j++] + refp[offset | 3] + CLIP_MIN];
+			image[offset | 4] = clip[dqc[j++] + refp[offset | 4] + CLIP_MIN];
+			image[offset | 5] = clip[dqc[j++] + refp[offset | 5] + CLIP_MIN];
+			image[offset | 6] = clip[dqc[j++] + refp[offset | 6] + CLIP_MIN];
+			image[offset | 7] = clip[dqc[j++] + refp[offset | 7] + CLIP_MIN];
+			offset += rpw;
+		}
+	}
+
+	private void wholePixelPredictor(short[] image, short[] refp, int[] clipW, int[] clipH, int mvx, int mvy, int pbx, int pby, boolean sparseDc) {
+		
+		// 7.9.1 Predictors
+
+		int rpw = clipW.length - PLANE_CLIP_RANGE; // The width of the current plane of the reference frame in pixels.
+		int offset = pby * rpw + pbx;
+		int pbyPlusMvyPlusPlaneClipMin = pby + mvy + PLANE_CLIP_MIN;
+		int offsetXPlusPlaneClipMin = pbx + mvx + PLANE_CLIP_MIN;
+		int offsetY;
+		if (sparseDc) {
+			for (int i = 0; i < 8; i++) {
+				offsetY = clipH[pbyPlusMvyPlusPlaneClipMin + i] * rpw;
+				image[offset    ] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin    ]] + CLIP_MIN];
+				image[offset | 1] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 1]] + CLIP_MIN];
+				image[offset | 2] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 2]] + CLIP_MIN];
+				image[offset | 3] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 3]] + CLIP_MIN];
+				image[offset | 4] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 4]] + CLIP_MIN];
+				image[offset | 5] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 5]] + CLIP_MIN];
+				image[offset | 6] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 6]] + CLIP_MIN];
+				image[offset | 7] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 7]] + CLIP_MIN];
+				offset += rpw;
+			}
+			return;
+		}
+		int j = 0;
+		
+		for (int i = 0; i < 8; i++) {
+			offsetY = clipH[pbyPlusMvyPlusPlaneClipMin + i] * rpw;
+			image[offset    ] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin    ]] + dqc[j++] + CLIP_MIN];
+			image[offset | 1] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 1]] + dqc[j++] + CLIP_MIN];
+			image[offset | 2] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 2]] + dqc[j++] + CLIP_MIN];
+			image[offset | 3] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 3]] + dqc[j++] + CLIP_MIN];
+			image[offset | 4] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 4]] + dqc[j++] + CLIP_MIN];
+			image[offset | 5] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 5]] + dqc[j++] + CLIP_MIN];
+			image[offset | 6] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 6]] + dqc[j++] + CLIP_MIN];
+			image[offset | 7] = clip[refp[offsetY + clipW[offsetXPlusPlaneClipMin + 7]] + dqc[j++] + CLIP_MIN];
+			offset += rpw;
+		}
+	}
+	
+	private void halfPixelPredictor(short[] image, short[] refp, int[] clipW, int[] clipH, int mvx, int mvy, int mvx2, int mvy2, int pbx, int pby, boolean sparseDc) {
+		
+		// 7.9.1 Predictors
+		
+		int rpw = clipW.length - PLANE_CLIP_RANGE; // The width of the current plane of the reference frame in pixels.
+		int offset = pby * rpw + pbx;
+		int pbyPlusMvyPlusPlaneClipMin = pby + mvy + PLANE_CLIP_MIN;
+		int pbyPlusMvy2PlusPlaneClipMin = pby + mvy2 + PLANE_CLIP_MIN;
+		int offsetXPlusPlaneClipMin = pbx + mvx + PLANE_CLIP_MIN;
+		int offsetX2PlusPlaneClipMin = pbx + mvx2 + PLANE_CLIP_MIN;
+		int offsetY;
+		int offsetY2;
+		if (sparseDc) {
+			for (int i = 0; i < 8; i++) {
+				offsetY = clipH[pbyPlusMvyPlusPlaneClipMin + i] * rpw;
+				offsetY2 = clipH[pbyPlusMvy2PlusPlaneClipMin + i] * rpw;
+				image[offset    ] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin    ]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin    ]] >> 1) + CLIP_MIN];
+				image[offset | 1] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 1]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 1]] >> 1) + CLIP_MIN];
+				image[offset | 2] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 2]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 2]] >> 1) + CLIP_MIN];
+				image[offset | 3] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 3]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 3]] >> 1) + CLIP_MIN];
+				image[offset | 4] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 4]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 4]] >> 1) + CLIP_MIN];
+				image[offset | 5] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 5]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 5]] >> 1) + CLIP_MIN];
+				image[offset | 6] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 6]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 6]] >> 1) + CLIP_MIN];
+				image[offset | 7] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 7]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 7]] >> 1) + CLIP_MIN];
+				offset += rpw;
+			}
+			return;
+		}
+		int j = 0;
+
+		for (int i = 0; i < 8; i++) {
+			offsetY = clipH[pbyPlusMvyPlusPlaneClipMin + i] * rpw;
+			offsetY2 = clipH[pbyPlusMvy2PlusPlaneClipMin + i] * rpw;
+			image[offset    ] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin    ]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin    ]] >> 1) + dqc[j++] + CLIP_MIN];
+			image[offset | 1] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 1]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 1]] >> 1) + dqc[j++] + CLIP_MIN];
+			image[offset | 2] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 2]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 2]] >> 1) + dqc[j++] + CLIP_MIN];
+			image[offset | 3] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 3]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 3]] >> 1) + dqc[j++] + CLIP_MIN];
+			image[offset | 4] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 4]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 4]] >> 1) + dqc[j++] + CLIP_MIN];
+			image[offset | 5] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 5]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 5]] >> 1) + dqc[j++] + CLIP_MIN];
+			image[offset | 6] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 6]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 6]] >> 1) + dqc[j++] + CLIP_MIN];
+			image[offset | 7] = clip[(refp[offsetY + clipW[offsetXPlusPlaneClipMin + 7]] + refp[offsetY2 + clipW[offsetX2PlusPlaneClipMin + 7]] >> 1) + dqc[j++] + CLIP_MIN];
+			offset += rpw;
+		}
+
+	}
+	
+	private void dequantization(short[] qmat0, short[] qmat, short[] coeffs, int nCoeffs) {
+		
+		// 7.9.2 Dequantization
+		
+		int zzi = 1; // The DCT coefficient index in zig-zag order
+				 // in opposite to the DCT coefficient index in natural order
+				 // == {int ci = ZIG_ZAG_SCAN[zzi];}.
+		
+		dqc[0] = (short) (coeffs[0] * qmat0[0]);
+		
+		for (; zzi < nCoeffs; zzi++) {
+			dqc[INVERSE_ZIG_ZAG_SCAN[zzi]] = (short) (coeffs[zzi] * qmat[zzi]);
+		}
+		for (; zzi < 64; zzi++) {
+			dqc[INVERSE_ZIG_ZAG_SCAN[zzi]] = 0;
+		}
+	}
+	
+	private void inverseDCT1D4Row(int shift) {
+		
+		// 7.9.3 The Inverse DCT
+		
+		// int t0, t1, t2, t3, t4, t5, t6, t7; // An 8-element array containing the current value of each signal line.
+		// int r; // A temporary value.
+		
+		int t0 = C4 * y0 >> 16;
+		int t2 = C6 * y2 >> 16;
+		int t3 = S6 * y2 >> 16;
+		int t4 = C7 * y1 >> 16;
+		int t5 = -(S3 * y3 >> 16);
+		int t6 = C3 * y3 >> 16;
+		int t7 = S7 * y1 >> 16;
+		int r = t4 + t5;
+		t5 = (short) (t4 - t5);
+		t5 = C4 * t5 >> 16;
+		t4 = r;
+		r = t7 + t6;
+		t6 = (short) (t7 - t6);
+		t6 = C4 * t6 >> 16;
+		t7 = r;
+		int t1 = t0 + t2;
+		t2 = t0 - t2;
+		r = t0 + t3;
+		t3 = t0 - t3;
+		t0 = r;
+		r = t6 + t5;
+		t5 = t6 - t5;
+		t6 = r;
+		dqc[shift    ] = (short) (t0 + t7);
+		dqc[shift | 1] = (short) (t1 + t6);
+		dqc[shift | 2] = (short) (t2 + t5);
+		dqc[shift | 3] = (short) (t3 + t4);
+		dqc[shift | 4] = (short) (t3 - t4);
+		dqc[shift | 5] = (short) (t2 - t5);
+		dqc[shift | 6] = (short) (t1 - t6);
+		dqc[shift | 7] = (short) (t0 - t7);
+	}
+	
+	private void inverseDCT1D3Row(int shift) {
+		
+		// 7.9.3 The Inverse DCT
+		
+		// int t0, t1, t2, t3, t4, t5, t6, t7; // An 8-element array containing the current value of each signal line.
+		// int r; // A temporary value.
+		
+		int t0 = C4 * y0 >> 16;
+		int t2 = C6 * y2 >> 16;
+		int t3 = S6 * y2 >> 16;
+		int t4 = C7 * y1 >> 16;
+		int t7 = S7 * y1 >> 16;
+		int t5 = C4 * t4 >> 16;
+		int t6 = C4 * t7 >> 16;
+		int t1 = t0 + t2;
+		t2 = t0 - t2;
+		int r = t0 + t3;
+		t3 = t0 - t3;
+		t0 = r;
+		r = t6 + t5;
+		t5 = t6 - t5;
+		t6 = r;
+		dqc[shift    ] = (short) (t0 + t7);
+		dqc[shift | 1] = (short) (t1 + t6);
+		dqc[shift | 2] = (short) (t2 + t5);
+		dqc[shift | 3] = (short) (t3 + t4);
+		dqc[shift | 4] = (short) (t3 - t4);
+		dqc[shift | 5] = (short) (t2 - t5);
+		dqc[shift | 6] = (short) (t1 - t6);
+		dqc[shift | 7] = (short) (t0 - t7);
+	}
+	
+	private void inverseDCT1D2Row(int shift) {
+		
+		// 7.9.3 The Inverse DCT
+		
+		// int t0, t4, t5, t6, t7; // An 8-element array containing the current value of each signal line.
+		// int r; // A temporary value.
+		
+		int t0 = C4 * y0 >> 16;
+		int t4 = C7 * y1 >> 16;
+		int t7 = S7 * y1 >> 16;
+		int t5 = C4 * t4 >> 16;
+		int t6 = C4 * t7 >> 16;
+		int r = t6 + t5;
+		t5 = t6 - t5;
+		t6 = r;
+		dqc[shift    ] = (short) (t0 + t7);
+		dqc[shift | 1] = (short) (t0 + t6);
+		dqc[shift | 2] = (short) (t0 + t5);
+		dqc[shift | 3] = (short) (t0 + t4);
+		dqc[shift | 4] = (short) (t0 - t4);
+		dqc[shift | 5] = (short) (t0 - t5);
+		dqc[shift | 6] = (short) (t0 - t6);
+		dqc[shift | 7] = (short) (t0 - t7);
+	}
+
+	private void inverseDCT1D1Row(int shift) {
+		
+		// 7.9.3 The Inverse DCT
+		
+		int t0 = C4 * y0 >> 16;
+		
+		dqc[shift    ] = t0;
+		dqc[shift | 1] = t0;
+		dqc[shift | 2] = t0;
+		dqc[shift | 3] = t0;
+		dqc[shift | 4] = t0;
+		dqc[shift | 5] = t0;
+		dqc[shift | 6] = t0;
+		dqc[shift | 7] = t0;
+	}
+	
+	private void inverseDCT2D(int maxRow) {
+		
+		// 7.9.3 The Inverse DCT
+		
+		int ci; // The column index.
+		int ri; // The row index.
+		int shift;
+		int y0, y1, y2, y3, y4, y5, y6, y7;
+		int t0, t1, t2, t3, t4, t5, t6, t7; // An 8-element array containing the current value of each signal line.
+		int r; // A temporary value.
+		
+		for (ri = 0; ri <= maxRow; ri++) {
+			shift = ri << 3;
+			y0 = dqc[shift    ];
+			y1 = dqc[shift | 1];
+			y2 = dqc[shift | 2];
+			y3 = dqc[shift | 3];
+			y4 = dqc[shift | 4];
+			y5 = dqc[shift | 5];
+			y6 = dqc[shift | 6];
+			y7 = dqc[shift | 7];
+			t0 = (short) (y0 + y4);
+			t0 = C4 * t0 >> 16;
+			t1 = (short) (y0 - y4);
+			t1 = C4 * t1 >> 16;
+			t2 = (C6 * y2 >> 16) - (S6 * y6 >> 16);
+			t3 = (S6 * y2 >> 16) + (C6 * y6 >> 16);
+			t4 = (C7 * y1 >> 16) - (S7 * y7 >> 16);
+			t5 = (C3 * y5 >> 16) - (S3 * y3 >> 16);
+			t6 = (S3 * y5 >> 16) + (C3 * y3 >> 16);
+			t7 = (S7 * y1 >> 16) + (C7 * y7 >> 16);
+			r = t4 + t5;
+			t5 = (short) (t4 - t5);
+			t5 = C4 * t5 >> 16;
+			t4 = r;
+			r = t7 + t6;
+			t6 = (short) (t7 - t6);
+			t6 = C4 * t6 >> 16;
+			t7 = r;
+			r = t0 + t3;
+			t3 = t0 - t3;
+			t0 = r;
+			r = t1 + t2;
+			t2 = t1 - t2;
+			t1 = r;
+			r = t6 + t5;
+			t5 = t6 - t5;
+			t6 = r;
+			dqc[shift    ] = (short) (t0 + t7);
+			dqc[shift | 1] = (short) (t1 + t6);
+			dqc[shift | 2] = (short) (t2 + t5);
+			dqc[shift | 3] = (short) (t3 + t4);
+			dqc[shift | 4] = (short) (t3 - t4);
+			dqc[shift | 5] = (short) (t2 - t5);
+			dqc[shift | 6] = (short) (t1 - t6);
+			dqc[shift | 7] = (short) (t0 - t7);
+		}
+		for (ci = 0; ci < 8; ci++) {
+			y0 = dqc[ci     ];
+			y1 = dqc[ 8 | ci];
+			y2 = dqc[16 | ci];
+			y3 = dqc[24 | ci];
+			y4 = dqc[32 | ci];
+			y5 = dqc[40 | ci];
+			y6 = dqc[48 | ci];
+			y7 = dqc[56 | ci];
+			t0 = (short) (y0 + y4);
+			t0 = C4 * t0 >> 16;
+			t1 = (short) (y0 - y4);
+			t1 = C4 * t1 >> 16;
+			t2 = (C6 * y2 >> 16) - (S6 * y6 >> 16);
+			t3 = (S6 * y2 >> 16) + (C6 * y6 >> 16);
+			t4 = (C7 * y1 >> 16) - (S7 * y7 >> 16);
+			t5 = (C3 * y5 >> 16) - (S3 * y3 >> 16);
+			t6 = (S3 * y5 >> 16) + (C3 * y3 >> 16);
+			t7 = (S7 * y1 >> 16) + (C7 * y7 >> 16);
+			r = t4 + t5;
+			t5 = (short) (t4 - t5);
+			t5 = C4 * t5 >> 16;
+			t4 = r;
+			r = t7 + t6;
+			t6 = (short) (t7 - t6);
+			t6 = C4 * t6 >> 16;
+			t7 = r;
+			r = t0 + t3;
+			t3 = t0 - t3;
+			t0 = r;
+			r = t1 + t2;
+			t2 = t1 - t2;
+			t1 = r;
+			r = t6 + t5;
+			t5 = t6 - t5;
+			t6 = r;
+			dqc[     ci] = (short) (t0 + t7) + 8 >> 4;
+			dqc[8  | ci] = (short) (t1 + t6) + 8 >> 4;
+			dqc[16 | ci] = (short) (t2 + t5) + 8 >> 4;
+			dqc[24 | ci] = (short) (t3 + t4) + 8 >> 4;
+			dqc[32 | ci] = (short) (t3 - t4) + 8 >> 4;
+			dqc[40 | ci] = (short) (t2 - t5) + 8 >> 4;
+			dqc[48 | ci] = (short) (t1 - t6) + 8 >> 4;
+			dqc[56 | ci] = (short) (t0 - t7) + 8 >> 4;
+		}
+	}
+	
+	private void inverseDCT2D3() {
+		
+		// 7.9.3 The Inverse DCT
+		
+		int ci; // The column index.
+		int ri; // The row index.
+		int shift = 0;
+		int t0, t4, t5, t6, t7; // An 8-element array containing the current value of each signal line.
+		int r; // A temporary value.
+			
+		y0 = dqc[0];
+		y1 = dqc[1];
+		inverseDCT1D2Row(shift);
+		shift = 8;
+		y0 = dqc[shift    ];
+		inverseDCT1D1Row(shift);
+		
+		for (ci = 0; ci < 8; ci++) {
+			int y0 = dqc[     ci];
+			int y1 = dqc[ 8 | ci];
+			t0 = C4 * y0 >> 16;
+			t4 = C7 * y1 >> 16;
+			t7 = S7 * y1 >> 16;
+			t5 = C4 * t4 >> 16;
+			t6 = C4 * t7 >> 16;
+			r = t6 + t5;
+			t5 = t6 - t5;
+			t6 = r;
+			dqc[     ci] = (short) (t0 + t7) + 8 >> 4;
+			dqc[8  | ci] = (short) (t0 + t6) + 8 >> 4;
+			dqc[16 | ci] = (short) (t0 + t5) + 8 >> 4;
+			dqc[24 | ci] = (short) (t0 + t4) + 8 >> 4;
+			dqc[32 | ci] = (short) (t0 - t4) + 8 >> 4;
+			dqc[40 | ci] = (short) (t0 - t5) + 8 >> 4;
+			dqc[48 | ci] = (short) (t0 - t6) + 8 >> 4;
+			dqc[56 | ci] = (short) (t0 - t7) + 8 >> 4;
+		}
+	}
+
+	private void inverseDCT2D6() {
+		
+		// 7.9.3 The Inverse DCT
+		
+		int ci; // The column index.
+		int ri; // The row index.
+		int shift = 0;
+		int t0, t1, t2, t3, t4, t5, t6, t7; // An 8-element array containing the current value of each signal line.
+		int r; // A temporary value.
+		
+		y0 = dqc[0];
+		y1 = dqc[1];
+		y2 = dqc[2];
+		inverseDCT1D3Row(shift);
+		shift = 8;
+		y0 = dqc[shift    ];
+		y1 = dqc[shift | 1];
+		inverseDCT1D2Row(shift);
+		shift = 16;
+		y0 = dqc[shift    ];
+		inverseDCT1D1Row(shift);
+		
+		for (ci = 0; ci < 8; ci++) {
+			int y1 = dqc[ 8 | ci];
+			int y2 = dqc[16 | ci];
+			t0 = C4 * dqc[ci] >> 16;
+			t2 = C6 * y2 >> 16;
+			t3 = S6 * y2 >> 16;
+			t4 = C7 * y1 >> 16;
+			t7 = S7 * y1 >> 16;
+			t5 = C4 * t4 >> 16;
+			t6 = C4 * t7 >> 16;
+			t1 = t0 + t2;
+			t2 = t0 - t2;
+			r = t0 + t3;
+			t3 = t0 - t3;
+			t0 = r;
+			r = t6 + t5;
+			t5 = t6 - t5;
+			t6 = r;
+			dqc[     ci] = (short) (t0 + t7) + 8 >> 4;
+			dqc[8  | ci] = (short) (t1 + t6) + 8 >> 4;
+			dqc[16 | ci] = (short) (t2 + t5) + 8 >> 4;
+			dqc[24 | ci] = (short) (t3 + t4) + 8 >> 4;
+			dqc[32 | ci] = (short) (t3 - t4) + 8 >> 4;
+			dqc[40 | ci] = (short) (t2 - t5) + 8 >> 4;
+			dqc[48 | ci] = (short) (t1 - t6) + 8 >> 4;
+			dqc[56 | ci] = (short) (t0 - t7) + 8 >> 4;
+		}
+	}
+
+	private void inverseDCT2D10() {
+		
+		// 7.9.3 The Inverse DCT
+		
+		int ci; // The column index.
+		int ri; // The row index.
+		int shift = 0;
+		int t0, t1, t2, t3, t4, t5, t6, t7; // An 8-element array containing the current value of each signal line.
+		int r; // A temporary value.
+
+		y0 = dqc[0];
+		y1 = dqc[1];
+		y2 = dqc[2];
+		y3 = dqc[3];
+		inverseDCT1D4Row(shift);
+		shift = 8;
+		y0 = dqc[shift    ];
+		y1 = dqc[shift | 1];
+		y2 = dqc[shift | 2];
+		inverseDCT1D3Row(shift);
+		shift = 16;
+		y0 = dqc[shift    ];
+		y1 = dqc[shift | 1];
+		inverseDCT1D2Row(shift);
+		shift = 24;
+		y0 = dqc[shift    ];
+		inverseDCT1D1Row(shift);
+		
+		for (ci = 0; ci < 8; ci++) {
+			int y1 = dqc[ 8 | ci];
+			int y2 = dqc[16 | ci];
+			int y3 = dqc[24 | ci];
+			t0 = C4 * dqc[ci] >> 16;
+			t2 = C6 * y2 >> 16;
+			t3 = S6 * y2 >> 16;
+			t4 = C7 * y1 >> 16;
+			t5 = -(S3 * y3 >> 16);
+			t6 = C3 * y3 >> 16;
+			t7 = S7 * y1 >> 16;
+			r = t4 + t5;
+			t5 = (short) (t4 - t5);
+			t5 = C4 * t5 >> 16;
+			t4 = r;
+			r = t7 + t6;
+			t6 = (short) (t7 - t6);
+			t6 = C4 * t6 >> 16;
+			t7 = r;
+			t1 = t0 + t2;
+			t2 = t0 - t2;
+			r = t0 + t3;
+			t3 = t0 - t3;
+			t0 = r;
+			r = t6 + t5;
+			t5 = t6 - t5;
+			t6 = r;
+			dqc[     ci] = (short) (t0 + t7) + 8 >> 4;
+			dqc[8  | ci] = (short) (t1 + t6) + 8 >> 4;
+			dqc[16 | ci] = (short) (t2 + t5) + 8 >> 4;
+			dqc[24 | ci] = (short) (t3 + t4) + 8 >> 4;
+			dqc[32 | ci] = (short) (t3 - t4) + 8 >> 4;
+			dqc[40 | ci] = (short) (t2 - t5) + 8 >> 4;
+			dqc[48 | ci] = (short) (t1 - t6) + 8 >> 4;
+			dqc[56 | ci] = (short) (t0 - t7) + 8 >> 4;
+		}
+	}
+	
+	private void horizontalFilter(short[] recp, short[] lflim, int fx, int fy, int rpw){
+		
+		// 7.10.1 Horizontal Filter
+		
+		int r; // The edge detector response.
+		int by; // The vertical pixel index in the block.
+		int pi = fy * rpw + fx; // Pixelindex.
+		int piPlus1 = pi + 1;
+		int piPlus2 = pi + 2;
+		
+		for (by = 0; by < 8; by++) {
+			r = recp[pi] - 3 * recp[piPlus1] + 3 * recp[piPlus2] - recp[pi + 3] + 4 >> 3;
+			recp[piPlus1] = clip[recp[piPlus1] + lflim[r + FILTER_MIN] + CLIP_MIN];
+			recp[piPlus2] = clip[recp[piPlus2] - lflim[r + FILTER_MIN] + CLIP_MIN];
+			pi += rpw;
+			piPlus1 = pi + 1;
+			piPlus2 = pi + 2;
+		}
+	}
+	
+	private void verticalFilter(short[] recp, short[] lflim, int fx, int fy, int rpw){
+		
+		// 7.10.2 Vertical Filter
+		
+		int r; // The edge detector response.
+		int bx; // The horizontal pixel index in the block.
+		int pi = fy * rpw + fx; // Pixelcoordinate.
+		int piPlusRpw = pi + rpw;
+		int piPlus2Rpw = piPlusRpw + rpw;
+		int piPlus3Rpw = piPlus2Rpw + rpw;
+		int piPlusRpwPlusBx;
+		int piPlus2RpwPlusBx;
+		
+		for (bx = 0; bx < 8; bx++) {
+			piPlusRpwPlusBx = piPlusRpw + bx;
+			piPlus2RpwPlusBx = piPlus2Rpw + bx;
+			r = recp[pi + bx] - 3 * recp[piPlusRpwPlusBx] + 3 * recp[piPlus2RpwPlusBx] - recp[piPlus3Rpw + bx] + 4 >> 3;
+			recp[piPlusRpwPlusBx] = clip[recp[piPlusRpwPlusBx] + lflim[r + FILTER_MIN] + CLIP_MIN];
+			recp[piPlus2RpwPlusBx] = clip[recp[piPlus2RpwPlusBx] - lflim[r + FILTER_MIN] + CLIP_MIN];
+		}
+	}
+
+	boolean display() {
+		if (ncbs == 0 || externFrameCount == internFrameCount) {
+			return false;
+		}
+
+		py = ref[0]; // Y
+		pv = ref[1]; // Cb
+		pu = ref[2]; // Cr
+		
+		if (internFrameCount == externFrameCount + 1 && !restart) {
+			super.display(pixelOffset, pixelRange);
+		} else {
+			yBStart[0] = yBStart[1] = yBStart[2] = 0;
+			yBEnd[0] = yBLength[0];
+			yBEnd[1] = yBEnd[2] = yBLength[1];
+			super.display(0, maximumPixelSize);
+		}
+		externFrameCount = internFrameCount;
+		return true;
+	}
+
+	
+	/**
+	 * Frees all system resources, which are bounded to this object.
+	 */
+	public void close() {
+		super.close();
+		int i, j, k;
+		
+		if (image == null) {
+			return;
+		}
+		image[0] = null;
+		image[1] = null;
+		image[2] = null;
+		image = null;
+		ref[0] = null;
+		ref[1] = null;
+		ref[2] = null;
+		ref = null;
+		goldRef[0] = null;
+		goldRef[1] = null;
+		goldRef[2] = null;
+		goldRef = null;
+		qis = null;
+		for (i = 0; i < bCoded.length; i++) {
+			bCoded[i] = null;
+		}
+		bCoded = null;
+		for (i = 0; i < oneBytesBytes.length; i++) {
+			oneBytesBytes[i] = null;
+		}
+		oneBytesBytes = null;
+		cbIndex = null;
+		ncbIndex = null;
+		cifbIndex = null;
+		qiis = null;
+		mbMode = null;
+		mbiToSbiLmbiMapping = null;
+		for (i = 0; i < lflim.length; i++) {
+			lflim[i] = null;
+		}
+		lflim = null;
+		nCoeffs = null;
+		tis = null;
+		
+		byte[][] mVectsPointer;
+	
+		for (i = 0; i < mVects.length; i++) {
+			mVectsPointer = mVects[i];
+			for (j = 0; j < mVectsPointer.length; j++) {
+				mVectsPointer[j] = null;
+			}
+			mVectsPointer = null;
+		}
+		mVects = null;
+		
+		int[][] rasterOrderToCodedOrderMappingPointer;
+		
+		for (i = 0; i < rasterOrderToCodedOrderMapping.length; i++) {
+			rasterOrderToCodedOrderMappingPointer = rasterOrderToCodedOrderMapping[i];
+			for (j = 0; j < rasterOrderToCodedOrderMappingPointer.length; j++) {
+				rasterOrderToCodedOrderMappingPointer[j] = null;
+			}
+			rasterOrderToCodedOrderMappingPointer = null;
+		}
+		rasterOrderToCodedOrderMapping = null;
+		for (i = 0; i < coeffs.length; i++) {
+			coeffs[i] = null;
+		}
+		coeffs = null;
+		mAlphabet = null;
+		dqc = null;
+		biToMbiMapping = null;
+		lastDc = null;
+		spipp = null;
+		pli = null;
+		coeffsValues = null;
+		planeWidthClip[0] = null;
+		planeWidthClip[1] = null; // No planeWidthClip[2] = null; because third planeWidthClip array is a reused second one.
+		planeWidthClip = null;
+		planeHeightClip[0] = null;
+		planeHeightClip[1] = null; // No planeHeightClip[2] = null; because third planeHeightClip array is a reused second one.
+		planeHeightClip = null;
+		blockCoordinateX = null;
+		blockCoordinateY = null;
+		sbpCodedBits = null;
+		sbfCodedBits = null;
+		bits = null;
+		zeroBytes = null;
+		oneBytes = null;
+		isNb = null;
+		xBLength = null;
+	 	yBLength = null;
+		yBStart = null;
+		yBEnd = null;
+		qcbIndex = root;
+		while (qcbIndex.unmorphableNext != qcbIndex) {
+			Node pointer = qcbIndex.unmorphableNext;
+			
+			qcbIndex = null;
+			qcbIndex = pointer;
+		}
+		qcbIndex = null;
+	}
+
+	private Node rebuildIntraCbIndexQueue(int size, int indices[], Node node) {
+		for (int i = 0; i < size; i++) {
+			node = put(indices[i], node);
+		}
+		return node;
+	}
+	
+	private Node put(int i, Node node) {
+		Node pointer = node;
+		
+		while (pointer.index != i) {
+			pointer = pointer.unmorphableNext;
+		}
+		pointer.previous = node;
+		pointer.next = pointer;
+		
+		node.next = pointer;
+		node = pointer;
+		
+		return node;
+	}
+	
+	private Node generate(int i, Node node) {
+		Node pointer = new Node();
+		
+		node.unmorphableNext = pointer;
+		node = pointer;
+		node.index = i;
+		
+		return node;
+	}
+		
+	private Node remove(Node node) {
+		Node pointer = node.previous;
+		
+		pointer.next = node.next;
+		node = pointer;
+
+		return pointer;
+	}
+	
+	private boolean traversable(Node node) {
+		return node.next != node ? true : false;
+	}
+	
+	private class Node {
+		Node next = this;
+		Node previous;
+		Node unmorphableNext = this;
+		int index = -1;
+	}
+}

Added: trunk/rhea/com/meviatronic/zeus/pollux/VideoReader.java
===================================================================
--- trunk/rhea/com/meviatronic/zeus/pollux/VideoReader.java	                        (rev 0)
+++ trunk/rhea/com/meviatronic/zeus/pollux/VideoReader.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,702 @@
+/* Pollux, a fast Theora decoder created by Michael Scheerer.
+ *
+ * Pollux decoder (c) 2010 Michael Scheerer www.meviatronic.com
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package com.meviatronic.zeus.pollux;
+
+import com.meviatronic.zeus.castor.*;
+import com.meviatronic.zeus.helen.*;
+import org.xiph.ogg.*;
+
+import java.io.*;
+import java.awt.*;
+import java.awt.image.*;
+
+/**
+ * The <code>VideoReader</code> class provides all necessary video format detection related methods.
+ * The <code>VideoReader</code> class stors also video header related data.
+ *
+ * @author	Michael Scheerer
+ */
+public final class VideoReader extends AudioReader {
+	
+	private final static byte ZIG_ZAG_SCAN[] = {
+		 0,  1,  5,  6, 14, 15, 27, 28,
+		 2,  4,  7, 13, 16, 26, 29, 42,
+		 3,  8, 12, 17, 25, 30, 41, 43,
+		 9, 11, 18, 24, 31, 40, 44, 53,
+		10, 19, 23, 32, 39, 45, 52, 54,
+		20, 22, 33, 38, 46, 51, 55, 60,
+		21, 34, 37, 47, 50, 56, 59, 61,
+		35, 36, 48, 49, 57, 58, 62, 63
+	};
+	
+	private int byteIdx;
+	private byte[] data;
+	private int bitIdx;
+	private int packetByteIdx;
+	private int packetSize;
+	
+	// Theora header
+	int mbWidth;
+	int mbHeight;
+	int sbChromaWidth;
+	int sbChromaHeight;
+	int sbLumaWidth;
+	int sbLumaHeight;
+	public int codedPictureWidth;
+	public int codedPictureHeight;
+	public int pictureRegionW;
+	public int pictureRegionH;
+	public int pictureRegionX;
+	public int pictureRegionY;
+	private int colorSpace;
+	private int videoBitrate;
+	private int qualityHint;
+	int keyFrameNumberGranuleShift;
+	int chromaFormat;
+	public Dimension aspectRatio;
+	public double frameRate;
+	int macroblocks;
+	int superblocks;
+	int blocks;
+	private int versionRevisionNumber;
+	// Theora extended header
+	private short[] acScale = new short[64]; // A 64-element array of scale
+	private short[] dcScale = new short[64];
+	short [][][][] qmat = new short[2][3][64][64]; // A 64-element array of quantization values for each DCT coefficient in natural order.
+	
+	private short[][] bms; // A NBMS/64 array containing the base matrices.
+	private short[][] nqrs = new short[2][3]; // A 2/3 array containing the number of quant
+	// ranges for a given qti and pli, respectively. This is at most 63.
+	private short[][][] qrSizes = new short[2][3][63]; // A 2/3/63 array of the sizes of
+	// each quant range for a given qti and pli, respectively.
+	// Only the first NQRS[qti ][pli] values are used.
+	private short[][][] qrbmis = new short[2][3][64]; // A 2/3/64 array of the
+	// bmi’s used for each quant range for a given qti and pli, respectively.
+	// Only the first (NQRS[qti ][pli] + 1) values used
+	private HuffTreeEntry[] hts = new HuffTreeEntry[80]; // An 80-element array of Huffman tables
+	// with up to 32 entries each.
+	private int entries;
+	
+	byte[] lflims = new byte[64];
+	
+	private Tag tag;
+	
+	public void loadPacket(byte[] buf, int start, int bytes){
+		byteIdx = start;
+		data = buf;
+		bitIdx = BYTELENGTH;
+		packetByteIdx = 0;
+		packetSize = bytes;
+	}
+
+	private void verifyFirstPacket() throws IOException, EndOfPacketException {
+		// Identification header type 0x80, comment header type 0x81, setup header type 0x82.
+		// This distinguishes them from video data packets
+		// in which the first bit is unset.
+		// packetType = get(8);
+		
+		if (get(8) != 3) {
+			throw new InterruptedIOException("Wrong major version");
+		}
+		if (get(8) != 2) {
+			throw new InterruptedIOException("Wrong minor version");
+		}
+		
+		versionRevisionNumber = get(8);
+		
+		codedPictureWidth = (mbWidth = get(16)) << 4;
+		codedPictureHeight = (mbHeight = get(16)) << 4;
+		pictureRegionW = get(24);
+		pictureRegionH = get(24);
+		pictureRegionX = get(8);
+		// Theora uses a right-handed coordinate system, while applications expect a left-handed one, so:
+		pictureRegionY = codedPictureHeight - pictureRegionH - get(8);
+
+		int framerateNumerator = get(32);
+		
+		int framerateDenominator = get(32);
+		
+		int aspectRatioNumerator = get(24);
+		
+		int aspectRatioDenominator = get(24);
+		
+		colorSpace = get(8);
+		videoBitrate = get(24);
+		qualityHint = get(6);
+		keyFrameNumberGranuleShift = get(5);
+		chromaFormat = get(2);
+		if (get(3) != 0) {
+			throw new InterruptedIOException("Reserved values not zero");
+		}
+
+		if (codedPictureWidth * codedPictureHeight > Integer.MAX_VALUE) {
+			throw new InterruptedIOException("Resolution overflow - Java cannot handle images with the size 2^40");
+		}
+		if (codedPictureWidth < pictureRegionW || codedPictureHeight < pictureRegionH) {
+			throw new InterruptedIOException("Picture region must be less/equal the coded frame");
+		}
+		if (mbWidth == 0 || mbHeight == 0) {
+			throw new InterruptedIOException("Wrong frame size in macroblocks");
+		}
+		if (pictureRegionW + pictureRegionX > codedPictureWidth || pictureRegionH + pictureRegionY > codedPictureHeight) {
+			throw new InterruptedIOException("Wrong picture region offset in pixels");
+		}
+		if (framerateNumerator == 0 || framerateDenominator == 0) {
+			throw new InterruptedIOException("Wrong frame rate");
+		} else {
+			frameRate = framerateNumerator / (double) framerateDenominator;
+		}
+		if (aspectRatioNumerator == 0 || aspectRatioDenominator == 0) {
+			aspectRatioNumerator = 1;
+			aspectRatioDenominator = 1;
+		}
+				
+		aspectRatio = new Dimension(aspectRatioNumerator, aspectRatioDenominator);
+			
+		if (chromaFormat == 1) {
+			throw new InterruptedIOException("Wrong color space");
+		}
+
+		macroblocks = mbWidth * mbHeight;
+		sbLumaWidth = (mbWidth + 1) / 2;
+		sbLumaHeight = (mbHeight + 1) / 2;
+		if (chromaFormat == 0) {
+			sbChromaWidth = (mbWidth + 3) / 4;
+			sbChromaHeight = (mbHeight + 3) / 4;
+			blocks = macroblocks * 6;
+		} else if (chromaFormat == 2) {
+			sbChromaWidth = (mbWidth + 3) / 4;
+			sbChromaHeight = (mbHeight + 1) / 2;
+			blocks = macroblocks * 8;
+		} else {
+			sbChromaWidth = (mbWidth + 1) / 2;
+			sbChromaHeight = (mbHeight + 1) / 2;
+			blocks = macroblocks * 12;
+		}
+		superblocks = sbLumaWidth * sbLumaHeight + 2 * sbChromaWidth * sbChromaHeight;
+	}
+	
+	private final void verifySecondPacket() throws IOException, EndOfPacketException {
+		try {
+			tag = new OggTag(this, false);
+			((OggTag) tag).decode();
+		} catch (Exception e) {
+			if (e instanceof IOException) {
+				throw new InterruptedIOException(e.getMessage());
+			}
+		}
+	}
+
+	private final void verifyThirdPacket() throws IOException, EndOfPacketException {
+		
+		// 6.4.1 Loop Filter Limit Table Decode
+		
+		int nbits = get(3); // The size of values being read in the current table.
+		
+		int qi; // The quantization index.
+		
+		for (qi = 0; qi < 64; qi++) {
+			lflims[qi] = (byte) get(nbits);
+		}
+		
+		// 6.4.2 Quantization Parameters Decode
+		
+		int qti; // A quantization type index. See Table 3.1.
+		int qtj; // A quantization type index.
+		int pli; // A color plane index. See Table 2.1.
+		int plj; // A color plane index.
+		int ci;  // The DCT coefficient index.
+		int bmi; // The base matrix index.
+		int qri; // The quant range index.
+		int newqr; // Flag that indicates a new set of quant ranges will be defined.
+		int rpqr; // Flag that indicates the quant ranges o copy will come from the same color plane.
+		int nbms; // The number of base matrices
+	
+		nbits = get(4) + 1;
+		
+		for (qi = 0; qi < 64; qi++) {
+			acScale[qi] = (short) get(nbits);
+		}
+		
+		nbits = get(4) + 1;
+		
+		for (qi = 0; qi < 64; qi++) {
+			dcScale[qi] = (short) get(nbits);
+		}
+		
+		nbms = get(9) + 1;
+		
+		if (nbms > 384) {
+			throw new InterruptedIOException("Base matrice number to high");
+		}
+		
+		bms = new short[nbms][64];
+		short[] bmsPointer;
+		
+		for (bmi = 0; bmi < nbms; bmi++) {
+			bmsPointer = bms[bmi];
+			for (ci = 0; ci < 64; ci++) {
+				bmsPointer[ci] = (short) get(8);
+			}
+		}
+		
+		for (qti = 0; qti < 2; qti++) {
+			for (pli = 0; pli < 3; pli++) {
+				if (qti > 0 || pli > 0) {
+					newqr = get1();
+				} else {
+					newqr = 1;
+				}
+				if (newqr == 0) {
+					if (qti > 0) {
+						rpqr = get1();
+					} else {
+						rpqr = 0;
+					}
+					if (rpqr == 1) {
+						qtj = qti - 1;
+						plj = pli;
+					} else {
+						qtj = (3 * qti + pli - 1) / 3;
+						plj = (pli + 2) % 3;
+					}
+					nqrs[qti][pli] = nqrs[qtj][plj ];
+					qrSizes[qti][pli] = qrSizes[qtj][plj];
+					qrbmis[qti][pli] = qrbmis[qtj][plj];
+				} else {
+					qri = qi = 0;
+
+					int check = get(ilog(nbms - 1));
+					
+					if (check >= nbms) {
+						throw new InterruptedIOException("Quant range size exceeds base matrice number");
+					}
+					qrbmis[qti][pli][qri] = (short) check;
+					
+					do {
+						qrSizes[qti][pli][qri] = (short) (get(ilog(62 - qi)) + 1);
+						qi += qrSizes[qti][pli][qri];
+						qri++;
+						qrbmis[qti][pli][qri] = (short) get(ilog(nbms - 1));
+					} while (qi < 63);
+					if (qi > 63) {
+						throw new InterruptedIOException("Quantization index exceeds 63");
+					}
+					nqrs[qti][pli] = (short) qri;
+				}
+			}
+		}
+
+		// 6.4.4 DCT Token Huffman Tables
+		
+		int hti; // The index of the current Huffman table to use.
+		
+		HuffTreeEntry entry;
+		
+		for (hti = 0; hti < 80; hti++) {
+			entry = new HuffTreeEntry();
+			entries = 0;
+			buildTree(entry, 0);
+			if (!entry.sparse) {
+				deflateTree(entry);
+				pruneTree(entry);
+			}
+			hts[hti] = entry;
+		}
+		
+		// 6.4.3 Computing all 384 Quantization Matrixes
+		
+		short[][][] qmatOuterPointer;
+		short[][] qmatInnerPointer;
+		
+		for (qti = 0; qti < qmat.length; qti++) {
+			qmatOuterPointer = qmat[qti];
+			for (pli = 0; pli < qmatOuterPointer.length; pli++) {
+				qmatInnerPointer = qmatOuterPointer[pli];
+				for (qi = 0; qi < qmatInnerPointer.length; qi++) {
+					computeQuantizationMatrix(qmatInnerPointer[qi], qti, pli, qi);
+				}
+			}
+		}
+	}
+	// 6.4.3 Computing a Quantization Matrix
+	private short[] computeQuantizationMatrix(short[] qmat, int qti, int pli, int qi) {
+		int ci; // The DCT coefficient index.
+		int bmi; // The base matrix index.
+		int bmj; // The base matrix index.
+		int qri; // The quant range index.
+		int qiStart = 0; // The left end-point of the qi range.
+		int qiEnd = 0; // The right end-point of the qi range.
+		int qmin; // The minimum quantization value allowed for the current coefficient.
+		int qscale; // The current scale value.
+		
+		for (qri = 0; qri < 63; qri++) {
+			qiEnd += qrSizes[qti][pli][qri];
+			if (qiEnd >= qi && qiStart <= qi) {
+				break;
+			}
+			qiStart = qiEnd;
+		}
+		
+		short qrSizesValue = qrSizes[qti][pli][qri];
+		int bmci; // A value containing the interpolated base matrix.
+		
+		bmi = qrbmis[qti][pli][qri];
+		bmj = qrbmis[qti][pli][qri + 1];
+		
+		short[] bmsPointer = bms[bmi];
+		short[] bmsPointer1 = bms[bmj];
+		
+		for (ci = 0, qmin = 16; ci < 64; ci++) {
+			bmci = (2 * (qiEnd - qi) * bmsPointer[ci] + 2 * (qi - qiStart) * bmsPointer1[ci] + qrSizesValue) / (2 * qrSizesValue);
+			if (ci > 0 && qti == 0) {
+				qmin = 8;
+			} else if (ci == 0 && qti == 1) {
+				qmin = 32;
+			}
+			if (ci ==0) {
+				qscale = dcScale[qi];
+			} else {
+				qscale = acScale[qi];
+			}
+			qmat[ZIG_ZAG_SCAN[ci]] = (short) Math.max(qmin, Math.min((qscale * bmci / 100) << 2, 4096));
+		}
+			
+		return qmat;
+	}
+	
+	public void readMediaInformation(Packet op) throws IOException, EndOfPacketException {
+		
+		if(op == null) {
+			throw new InterruptedIOException("Packet is null");
+		}
+
+		loadPacket(op.packetBase, op.packet, op.bytes);
+	
+        byte[] buffer = new byte[6];
+		
+		int packetType = get(8);
+		
+		for (int i = 0; i < buffer.length; i++) {
+			buffer[i] = (byte) get(8);
+		}
+		
+		if (!new String(buffer).equals("theora")) {
+			throw new InterruptedIOException("No first packet");
+		}
+	    
+		if (packetType == 0x80 && op.bos != 0) {
+			verifyFirstPacket();
+		} else if (packetType == 0x81 && op.bos == 0) {
+			verifySecondPacket();
+		} else if (packetType == 0x82 && op.bos == 0) {
+			verifyThirdPacket();
+		} else {
+			throw new InterruptedIOException("Wrong packet order");
+		}
+	}
+
+	int get1() throws IOException, EndOfPacketException {
+		if (packetSize == 0) {
+			throw new EndOfPacketException();
+		}
+		if (packetByteIdx >= packetSize && packetSize > 0) {
+			throw new InterruptedIOException("Illegal truncate packet decoding mode");
+		}
+
+		bitIdx--;
+		
+		int val = data[byteIdx] >>> bitIdx & 1;
+
+		if (bitIdx == 0) {
+			bitIdx = BYTELENGTH;
+			byteIdx++;
+			packetByteIdx++;
+		}
+		return val;
+	}
+	
+	/**
+	 * Returns an integer with the length i
+	 *
+	 * @return                               the integer value
+	 * @param i                              the length in bits
+	 * @exception IOException                if the bits can't be retrieved
+	 * @exception EndOfPacketExeption        if an end of packet occur
+	 */
+	public int get(int i) throws IOException, EndOfPacketException {
+		if (i <= 0) {
+			return 0;
+		}
+		if (packetSize == 0) {
+			throw new EndOfPacketException();
+		}
+		if (packetByteIdx >= packetSize && packetSize > 0) {
+			throw new InterruptedIOException("Illegal truncate packet decoding mode");
+		}
+
+		int val = 0;
+		
+		int prefix = data[byteIdx] & BITMASK[bitIdx];
+		
+		bitIdx -= i;
+		
+		if (bitIdx > 0) {
+			return prefix >>> bitIdx;
+		} else {
+			bitIdx += BYTELENGTH;
+			byteIdx++;
+			packetByteIdx++;
+			if (bitIdx < BYTELENGTH) {
+				if (packetByteIdx >= packetSize) {
+					throw new InterruptedIOException("Illegal truncate packet decoding mode");
+				}
+				val = data[byteIdx] & 0xFF;
+			}
+			if (bitIdx <= 0) {
+				bitIdx += BYTELENGTH;
+				val <<= BYTELENGTH;
+				prefix <<= BYTELENGTH;
+				byteIdx++;
+				packetByteIdx++;
+				if (bitIdx < BYTELENGTH) {
+					if (packetByteIdx >= packetSize) {
+						throw new InterruptedIOException("Illegal truncate packet decoding mode");
+					}
+					val |= data[byteIdx] & 0xFF;
+				}
+				if (bitIdx <= 0) {
+					bitIdx += BYTELENGTH;
+					val <<= BYTELENGTH;
+					prefix <<= BYTELENGTH;
+					byteIdx++;
+					packetByteIdx++;
+					if (bitIdx < BYTELENGTH) {
+						if (packetByteIdx >= packetSize) {
+							throw new InterruptedIOException("Illegal truncate packet decoding mode");
+						}
+						val |= data[byteIdx] & 0xFF;
+					}
+					if (bitIdx <= 0) {
+						bitIdx += BYTELENGTH;
+						val <<= BYTELENGTH;
+						prefix <<= BYTELENGTH;
+						byteIdx++;
+						packetByteIdx++;
+						if (bitIdx < BYTELENGTH) {
+							if (packetByteIdx >= packetSize) {
+								throw new InterruptedIOException("Illegal truncate packet decoding mode");
+							}
+							val |= data[byteIdx] & 0xFF;
+						}
+					}
+				}
+			}
+		}
+		val >>>= bitIdx;
+		val |= prefix << BYTELENGTH - bitIdx;
+		return val;
+	}
+	
+	public String getOggCommentContent() {
+		return tag.toString();
+	}
+
+	final int getCodeWord(int bookNumber) throws IOException, EndOfPacketException {
+		HuffTreeEntry node = hts[bookNumber];
+		
+		while (node.value == -1){
+			node = node.childFeed[get(node.feed)];
+			if (node == null) {
+				return -1;
+			}
+		}
+		return node.value;
+	}
+	
+	/**
+	 * Frees all system resources, which are bounded to this object.
+	 */
+	public void close() {
+		super.close();
+		int i, j, k;
+		
+		if (hts != null) {
+			for (i = 0; i < 80; i++) {
+				closeTree(hts[i]);
+				hts[i] = null;
+			}
+			hts = null;
+		} else {
+			return;
+		}
+
+		tag.close();
+		tag = null;
+		
+		data = null;
+		lflims = null;
+		acScale = null;
+		dcScale = null;
+		for (i = 0; i < bms.length; i++) {
+			bms[i] = null;
+		}
+		bms = null;
+		for (i = 0; i < nqrs.length; i++) {
+			nqrs[i] = null;
+		}
+		nqrs = null;
+		
+		short[][] pointer;
+		
+		for (i = 0; i < qrSizes.length; i++) {
+			pointer = qrSizes[i];
+			for (j = 0; j < pointer.length; j++) {
+				pointer[j] = null;
+			}
+			pointer = null;
+		}
+		qrSizes = null;
+		for (i = 0; i < qrbmis.length; i++) {
+			pointer = qrbmis[i];
+			for (j = 0; j < pointer.length; j++) {
+				pointer[j] = null;
+			}
+			pointer = null;
+		}
+		qrbmis = null;
+		
+		short[][][] qmatOuterPointer;
+		short[][] qmatInnerPointer;
+		
+		for (i = 0; i < qmat.length; i++) {
+			qmatOuterPointer = qmat[i];
+			for (j = 0; j < qmatOuterPointer.length; j++) {
+				qmatInnerPointer = qmatOuterPointer[j];
+				for (k = 0; k < qmatInnerPointer.length; k++) {
+					qmatInnerPointer[k] = null;
+				}
+				qmatInnerPointer = null;
+			}
+			qmatOuterPointer = null;
+		}
+		qmat = null;
+	}
+
+	private void deflateTree(HuffTreeEntry node) {
+		int i, j, k, feedMinusOne, feedMinusOneMinusJ;
+		HuffTreeEntry nodeBase = node;
+			
+		for (node.feed = 2; node.feed < 33; node.feed++) {
+			k = 1 << node.feed;
+			HuffTreeEntry[] copy = new HuffTreeEntry[k];
+			
+			feedMinusOne = node.feed - 1;
+			for (i = 0; i < k; i++) {
+				for (j = 0; j < node.feed; j++) {
+					feedMinusOneMinusJ = feedMinusOne - j;
+					nodeBase = nodeBase.child[(i & 1 << feedMinusOneMinusJ) >>> feedMinusOneMinusJ];
+					if (nodeBase == null) {
+						node.feed--;
+						copy = null;
+						if (node.feed > 1) {
+							for (i = 0; i < node.childFeed.length; i++) {
+								deflateTree(node.childFeed[i]);
+							}
+						}
+						return;
+					}
+				}
+				copy[i] = nodeBase;
+				nodeBase = node;
+			}
+			for (i = 0; i < node.childFeed.length; i++) {
+				node.childFeed[i].dereferenced = true;
+			}
+			node.childFeed = copy;
+		}
+	}
+	
+	private void buildTree(HuffTreeEntry node, int depth) throws IOException, EndOfPacketException {
+		if(get1() == 1) {
+			if (depth == 0) {
+				node.sparse = true;
+			}
+			if (++entries > 32) {
+				throw new InterruptedIOException("Huffmann table entry overflow");
+			}
+			node.value = get(5);
+			return;
+		}
+		if (++depth > 32) {
+			throw new InterruptedIOException("Huffmann table depht overflow");
+		}
+		buildTree((node.child[0] = new HuffTreeEntry()), depth);
+		buildTree((node.child[1] = new HuffTreeEntry()), depth);
+	}
+	
+	private void pruneTree(HuffTreeEntry node) {
+		HuffTreeEntry left = node.child[0];
+		HuffTreeEntry right = node.child[1];
+		
+		if (left != null) {
+			pruneTree(left);
+			pruneTree(right);
+		}
+		if (node.dereferenced) {
+			node.child = null;
+			node = null;
+		} else {
+			if (node.child != node.childFeed) {
+				node.child = null;
+			}
+		}
+	}
+	
+	private void closeTree(HuffTreeEntry node) {
+		HuffTreeEntry nodeBase;
+		
+		for (int i = 0; i < node.childFeed.length; i++) {
+			nodeBase = node.childFeed[i];
+			if (nodeBase != null) {
+				closeTree(nodeBase);
+				nodeBase = null;
+			}
+		}
+		node.child = null;
+		node.childFeed = null;
+		node = null;
+	}
+	
+	private class HuffTreeEntry {
+		HuffTreeEntry[] child = new HuffTreeEntry[2];
+		HuffTreeEntry[] childFeed = child;
+		int value = -1;
+		boolean sparse;
+		byte feed = 1;
+		boolean dereferenced;
+	}
+}
+

Added: trunk/rhea/org/xiph/ogg/Packet.java
===================================================================
--- trunk/rhea/org/xiph/ogg/Packet.java	                        (rev 0)
+++ trunk/rhea/org/xiph/ogg/Packet.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,51 @@
+/* Ogg, created by Xiph,
+ * ported from C++ to Java and named as Jorbis framework.
+ *
+ * Ogg decoder (c) 2000 Xiph foundation www.xiph.org
+ * Jorbis framework (c) 2000 ymnk, JCraft,Inc. <ymnk at jcraft.com>
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package org.xiph.ogg;
+
+/**
+ * The <code>Packet</code> class provides all necessary packet related members.
+ *
+ * @author	Xip, JCraft (Port)
+ */
+public final class Packet{
+	public byte[] packetBase;
+	public int packet;
+	public int bytes;
+	public int bos;
+	public int eos;
+
+	public long granulepos;
+
+    /**
+     * sequence number for decode; the framing
+     * knows where there's a hole in the data,
+     * but we need coupling so that the codec
+     * (which is in a seperate abstraction
+     * layer) also knows about the gap
+     */
+	public long packetno;
+}

Added: trunk/rhea/org/xiph/ogg/Page.java
===================================================================
--- trunk/rhea/org/xiph/ogg/Page.java	                        (rev 0)
+++ trunk/rhea/org/xiph/ogg/Page.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,142 @@
+/* Ogg, created by Xiph,
+ * ported from C++ to Java and named as Jorbis framework.
+ *
+ * Ogg decoder (c) 2000 Xiph foundation www.xiph.org
+ * Jorbis framework (c) 2000 ymnk, JCraft,Inc. <ymnk at jcraft.com>
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.xiph.ogg;
+
+/**
+ * The <code>Page</code> class provides all necessary page related members.
+ * The CRC algorithm is delevoped based on public domain code by
+ * Ross Williams (ross at guest.adelaide.edu.au).
+ * A 32 bit CRC value (direct algorithm, initial val and final XOR = 0, generator polynomial=0x04c11db7) is used.
+ * The value is computed over the entire header (with the CRC field in the header set to zero)
+ * and then continued over the page.
+ * The CRC field is then filled with the computed value.
+ * This algorithm is taken from the Castor decoder.
+ *
+ * @author Xiph, JCraft (Port), Michael Scheerer (CRC)
+ */
+
+
+public final class Page {
+	
+	private static int[] crcTable;
+	
+	static {
+		int i, j, r;
+		
+		crcTable = new int[256];
+		
+		for (i = 0; i < 256; i++) {
+			r = i << 24;
+			
+			for (j = 0; j < 8; j++) {
+				if ((r & 0x80000000) != 0) {
+					r = r << 1 ^ 0x04C11DB7;
+				} else {
+					r <<= 1;
+				}
+			}
+			crcTable[i] = r;
+		}
+	}
+
+
+  	public byte[] header_base;
+  	public int header;
+  	public int header_len;
+  	public byte[] body_base;
+  	public int body;
+  	public int body_len;
+
+  	int version(){
+    	return header_base[header + 4] & 0xFF;
+  	}
+
+  	int continued() {
+    	return (header_base[header + 5] & 0x01);
+  	}
+
+  	public int bos() {
+    	return (header_base[header + 5] & 0x02);
+  	}
+
+  	public int eos() {
+    	return (header_base[header + 5] & 0x04);
+  	}
+
+  	public long granulepos() {
+    	long foo=header_base[header + 13] & 0xFF;
+    	foo = (foo << 8) | (header_base[header + 12] & 0xFF);
+    	foo = (foo << 8) | (header_base[header + 11] & 0xFF);
+    	foo = (foo << 8) | (header_base[header + 10] & 0xFF);
+    	foo = (foo << 8) | (header_base[header + 9] & 0xFF);
+    	foo = (foo << 8) | (header_base[header + 8] & 0xFF);
+    	foo = (foo << 8) | (header_base[header + 7] & 0xFF);
+    	foo = (foo << 8) | (header_base[header + 6] & 0xFF);
+    	return (foo);
+  	}
+
+  	public int serialno() {
+    	return (header_base[header + 14] & 0xFF) | ((header_base[header + 15] & 0xFF) << 8)
+        | ((header_base[header + 16] & 0xFF) << 16)
+        | ((header_base[header + 17] & 0xFF) << 24);
+  	}
+
+  	int pageno() {
+    	return (header_base[header + 18] & 0xFF) | ((header_base[header + 19] & 0xFF) << 8)
+        | ((header_base[header + 20] & 0xFF) << 16)
+        | ((header_base[header + 21] & 0xFF) << 24);
+  	}
+	
+	private int getChecksum(int crc, byte[] data, int i, int j) {
+		int k = i + j;
+		
+		for (; i < k; i++) {
+			crc = crc << 8 ^ crcTable[crc >>> 24 & 0xFF ^ data[i] & 0xFF];
+		}
+		return crc;
+	}
+	
+	private static int getChecksum(int crc, byte data) {
+		return crc << 8 ^ crcTable[crc >>> 24 & 0xFF ^ data & 0xFF];
+	}
+	
+	void checksum(){
+		int crc_reg = 0;
+	  
+	 	crc_reg = getChecksum(crc_reg, header_base, header, header_len);
+	 	crc_reg = getChecksum(crc_reg, body_base, body, body_len);
+	 
+    	header_base[header + 22] = (byte)crc_reg;
+    	header_base[header + 23] = (byte)(crc_reg >>> 8);
+    	header_base[header + 24] = (byte)(crc_reg >>> 16);
+    	header_base[header + 25] = (byte)(crc_reg >>> 24);
+	}
+	
+	public void close () {
+		header_base = null;
+		body_base = null;
+	}
+}

Added: trunk/rhea/org/xiph/ogg/StreamState.java
===================================================================
--- trunk/rhea/org/xiph/ogg/StreamState.java	                        (rev 0)
+++ trunk/rhea/org/xiph/ogg/StreamState.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,331 @@
+/* Ogg, created by Xiph,
+ * ported from C++ to Java and named as Jorbis framework.
+ *
+ * Ogg decoder (c) 2000 Xiph foundation www.xiph.org
+ * Jorbis framework (c) 2000 ymnk, JCraft,Inc. <ymnk at jcraft.com>
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package org.xiph.ogg;
+
+/**
+ * @author Xiph, JCraft (Port)
+ */
+public final class StreamState{
+  byte[] body_data; /* bytes from packet bodies */
+  int body_storage; /* storage elements allocated */
+  int body_fill; /* elements stored; fill mark */
+  private int body_returned; /* elements of fill returned */
+
+  int[] lacing_vals; /* The values that will go to the segment table */
+  long[] granule_vals; /* pcm_pos values for headers. Not compact
+   		   this way, but it is simple coupled to the
+   		   lacing fifo */
+  int lacing_storage;
+  int lacing_fill;
+  int lacing_packet;
+  int lacing_returned;
+
+  byte[] header=new byte[282]; /* working space for header encode */
+  int header_fill;
+
+  private int eos; /* set when we have buffered the last packet in the
+   	 logical bitstream */
+  private int bos; /* set after we've written the initial page
+   of a logical bitstream */
+  int serialno;
+  int pageno;
+  long packetno; /* sequence number for decode; the framing
+                      knows where there's a hole in the data,
+                      but we need coupling so that the codec
+                      (which is in a seperate abstraction
+                      layer) also knows about the gap */
+  long granulepos;
+
+  public StreamState(){
+    init();
+  }
+
+  StreamState(int serialno){
+    this();
+    init(serialno);
+  }
+
+  void init(){
+    body_storage=16*1024;
+    body_data=new byte[body_storage];
+    lacing_storage=1024;
+    lacing_vals=new int[lacing_storage];
+    granule_vals=new long[lacing_storage];
+  }
+
+  public void init(int serialno){
+    if(body_data==null){
+      init();
+    }
+    else{
+      for(int i=0; i<body_data.length; i++)
+        body_data[i]=0;
+      for(int i=0; i<lacing_vals.length; i++)
+        lacing_vals[i]=0;
+      for(int i=0; i<granule_vals.length; i++)
+        granule_vals[i]=0;
+    }
+    this.serialno=serialno;
+  }
+
+	
+	public void close() {
+    	body_data = null;
+    	lacing_vals = null;
+		granule_vals = null;
+		header = null;
+  	}
+
+  private void body_expand(int needed){
+    if(body_storage<=body_fill+needed){
+      body_storage+=(needed+1024);
+      byte[] foo=new byte[body_storage];
+      System.arraycopy(body_data, 0, foo, 0, body_data.length);
+      body_data=foo;
+    }
+  }
+
+  private void lacing_expand(int needed){
+    if(lacing_storage<=lacing_fill+needed){
+      lacing_storage+=(needed+32);
+      int[] foo=new int[lacing_storage];
+      System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
+      lacing_vals=foo;
+
+      long[] bar=new long[lacing_storage];
+      System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
+      granule_vals=bar;
+    }
+  }
+
+  public int packetout(Packet op){
+
+    /* The last part of decode. We have the stream broken into packet
+       segments.  Now we need to group them into packets (or return the
+       out of sync markers) */
+
+    int ptr=lacing_returned;
+
+    if(lacing_packet<=ptr){
+      return (0);
+    }
+
+    if((lacing_vals[ptr]&0x400)!=0){
+      /* We lost sync here; let the app know */
+      lacing_returned++;
+
+      /* we need to tell the codec there's a gap; it might need to
+         handle previous packet dependencies. */
+      packetno++;
+      return (-1);
+    }
+
+    /* Gather the whole packet. We'll have no holes or a partial packet */
+    {
+      int size=lacing_vals[ptr] & 0xff;
+      int bytes=0;
+
+      op.packetBase = body_data;
+      op.packet = body_returned;
+      op.eos = lacing_vals[ptr] & 0x200; /* last packet of the stream? */
+      op.bos = lacing_vals[ptr] & 0x100; /* first packet of the stream? */
+      bytes+=size;
+
+      while(size == 255){
+        int val = lacing_vals[++ptr];
+        size = val & 0xff;
+        if((val & 0x200) !=0 )
+          op.eos = 0x200;
+        bytes += size;
+      }
+
+      op.packetno=packetno;
+		op.granulepos=granule_vals[ptr];
+		
+      op.bytes=bytes;
+
+      body_returned+=bytes;
+
+      lacing_returned=ptr+1;
+    }
+    packetno++;
+    return (1);
+  }
+
+  // add the incoming page to the stream state; we decompose the page
+  // into packet segments here as well.
+
+  public int pagein(Page og){
+    byte[] header_base=og.header_base;
+    int header=og.header;
+    byte[] body_base=og.body_base;
+    int body=og.body;
+    int bodysize=og.body_len;
+    int segptr=0;
+
+    int version=og.version();
+    int continued=og.continued();
+    int bos=og.bos();
+    int eos=og.eos();
+    long granulepos=og.granulepos();
+    int _serialno=og.serialno();
+    int _pageno=og.pageno();
+    int segments=header_base[header+26]&0xff;
+
+    // clean up 'returned data'
+    {
+      int lr=lacing_returned;
+      int br=body_returned;
+
+      // body data
+      if(br!=0){
+        body_fill-=br;
+        if(body_fill!=0){
+          System.arraycopy(body_data, br, body_data, 0, body_fill);
+        }
+        body_returned=0;
+      }
+
+      if(lr!=0){
+        // segment table
+        if((lacing_fill-lr)!=0){
+          System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill-lr);
+          System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill-lr);
+        }
+        lacing_fill-=lr;
+        lacing_packet-=lr;
+        lacing_returned=0;
+      }
+    }
+
+    // check the serial number
+    if(_serialno!=serialno)
+      return (-1);
+    if(version>0)
+      return (-1);
+
+    lacing_expand(segments+1);
+
+    // are we in sequence?
+    if(_pageno!=pageno){
+      int i;
+
+      // unroll previous partial packet (if any)
+      for(i=lacing_packet; i<lacing_fill; i++){
+        body_fill-=lacing_vals[i]&0xff;
+        //System.out.println("??");
+      }
+      lacing_fill=lacing_packet;
+
+      // make a note of dropped data in segment table
+      if(pageno!=-1){
+        lacing_vals[lacing_fill++]=0x400;
+        lacing_packet++;
+      }
+
+      // are we a 'continued packet' page?  If so, we'll need to skip
+      // some segments
+      if(continued!=0){
+        bos=0;
+        for(; segptr<segments; segptr++){
+          int val=(header_base[header+27+segptr]&0xff);
+          body+=val;
+          bodysize-=val;
+          if(val<255){
+            segptr++;
+            break;
+          }
+        }
+      }
+    }
+
+    if(bodysize!=0){
+      body_expand(bodysize);
+      System.arraycopy(body_base, body, body_data, body_fill, bodysize);
+      body_fill+=bodysize;
+    }
+
+    {
+      int saved=-1;
+      while(segptr<segments){
+        int val=(header_base[header+27+segptr]&0xff);
+        lacing_vals[lacing_fill]=val;
+        granule_vals[lacing_fill]=-1;
+
+        if(bos!=0){
+          lacing_vals[lacing_fill]|=0x100;
+          bos=0;
+        }
+
+        if(val<255)
+          saved=lacing_fill;
+
+        lacing_fill++;
+        segptr++;
+
+        if(val<255)
+          lacing_packet=lacing_fill;
+      }
+
+      /* set the granulepos on the last pcmval of the last full packet */
+      if(saved!=-1){
+        granule_vals[saved]=granulepos;
+      }
+    }
+
+    if(eos!=0){
+      eos=1;
+      if(lacing_fill>0)
+        lacing_vals[lacing_fill-1]|=0x200;
+    }
+
+    pageno=_pageno+1;
+    return (0);
+  }
+
+  public int eof(){
+    return eos;
+  }
+
+  public int reset(){
+    body_fill=0;
+    body_returned=0;
+
+    lacing_fill=0;
+    lacing_packet=0;
+    lacing_returned=0;
+
+    header_fill=0;
+
+    eos=0;
+    bos=0;
+    pageno=-1;
+    packetno=0;
+    granulepos=0;
+    return (0);
+  }
+}

Added: trunk/rhea/org/xiph/ogg/SyncState.java
===================================================================
--- trunk/rhea/org/xiph/ogg/SyncState.java	                        (rev 0)
+++ trunk/rhea/org/xiph/ogg/SyncState.java	2010-03-27 16:16:05 UTC (rev 17092)
@@ -0,0 +1,282 @@
+/* Ogg, created by Xiph,
+ * ported from C++ to Java and named as Jorbis framework.
+ *
+ * Ogg decoder (c) 2000 Xiph foundation www.xiph.org
+ * Jorbis framework (c) 2000 ymnk, JCraft,Inc. <ymnk at jcraft.com>
+ *
+ * Many thanks to
+ *   Monty <monty at xiph.org> and
+ *   The XIPHOPHORUS Company http://www.xiph.org/ .
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+   
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+package org.xiph.ogg;
+
+// DECODING PRIMITIVES: packet streaming layer
+
+// This has two layers to place more of the multi-serialno and paging
+// control in the application's hands.  First, we expose a data buffer
+// using ogg_decode_buffer().  The app either copies into the
+// buffer, or passes it directly to read(), etc.  We then call
+// ogg_decode_wrote() to tell how many bytes we just added.
+//
+// Pages are returned (pointers into the buffer in ogg_sync_state)
+// by ogg_decode_stream().  The page is then submitted to
+// ogg_decode_page() along with the appropriate
+// ogg_stream_state* (ie, matching serialno).  We then get raw
+// packets out calling ogg_stream_packet() with a
+// ogg_stream_state.  See the 'frame-prog.txt' docs for details and
+// example code.
+
+// Race condition killed by MS (www.meviatronic.de).
+
+/**
+ * @author Xiph, JCraft (Port)
+ */
+public final class SyncState{
+	
+	// sync the stream.  This is meant to be useful for finding page
+  // boundaries.
+  //
+  // return values for this:
+  // -n) skipped n bytes
+  //  0) page not ready; more data (no bytes skipped)
+  //  n) page synced at current location; page length n bytes
+  private Page pageseek=new Page();
+  private byte[] chksum=new byte[4];
+	
+  public byte[] data;
+  int storage;
+  int fill;
+  int returned;
+
+  int unsynced;
+  int headerbytes;
+  int bodybytes;
+
+  public void close(){
+	  data=null;
+	  pageseek.close();
+	  pageseek = null;
+	  chksum = null;
+  }
+
+	public int buffer(int size){
+    // first, clear out any space that has been previously returned
+    if(returned!=0){
+      fill-=returned;
+      if(fill>0){
+        System.arraycopy(data, returned, data, 0, fill);
+      }
+      returned=0;
+    }
+
+    if(size>storage-fill){
+      // We need to extend the internal buffer
+      int newsize=size+fill+4096; // an extra page to be nice
+      if(data!=null){
+        byte[] foo=new byte[newsize];
+        System.arraycopy(data, 0, foo, 0, data.length);
+        data=foo;
+      }
+      else{
+        data=new byte[newsize];
+      }
+      storage=newsize;
+    }
+
+    return (fill);
+  }
+
+  public int wrote(int bytes){
+    if(fill+bytes>storage)
+      return (-1);
+    fill+=bytes;
+    return (0);
+  }
+
+  private int pageseek(Page og){
+    int page=returned;
+    int next;
+    int bytes=fill-returned;
+	 
+    if(headerbytes==0){
+      int _headerbytes, i;
+      if(bytes<27)
+        return (0); // not enough for a header
+
+      /* verify capture pattern */
+      if(data[page]!='O'||data[page+1]!='g'||data[page+2]!='g'
+          ||data[page+3]!='S'){
+        headerbytes=0;
+        bodybytes=0;
+
+        // search for possible capture
+        next=0;
+        for(int ii=0; ii<bytes-1; ii++){
+          if(data[page+1+ii]=='O'){
+            next=page+1+ii;
+            break;
+          }
+        }
+        //next=memchr(page+1,'O',bytes-1);
+        if(next==0)
+          next=fill;
+
+        returned=next;
+        return (-(next-page));
+      }
+      _headerbytes=(data[page+26]&0xff)+27;
+      if(bytes<_headerbytes)
+        return (0); // not enough for header + seg table
+
+      // count up body length in the segment table
+
+      for(i=0; i<(data[page+26]&0xff); i++){
+        bodybytes+=(data[page+27+i]&0xff);
+      }
+      headerbytes=_headerbytes;
+    }
+
+    if(bodybytes+headerbytes>bytes)
+      return (0);
+
+    // The whole test page is buffered.  Verify the checksum
+    //synchronized(chksum){
+      // Grab the checksum bytes, set the header field to zero
+
+      System.arraycopy(data, page+22, chksum, 0, 4);
+      data[page+22]=0;
+      data[page+23]=0;
+      data[page+24]=0;
+      data[page+25]=0;
+
+      // set up a temp page struct and recompute the checksum
+      Page log=pageseek;
+      log.header_base=data;
+      log.header=page;
+      log.header_len=headerbytes;
+
+      log.body_base=data;
+      log.body=page+headerbytes;
+      log.body_len=bodybytes;
+      log.checksum();
+
+      // Compare
+      if(chksum[0]!=data[page+22]||chksum[1]!=data[page+23]
+          ||chksum[2]!=data[page+24]||chksum[3]!=data[page+25]){
+        // D'oh.  Mismatch! Corrupt page (or miscapture and not a page at all)
+        // replace the computed checksum with the one actually read in
+        System.arraycopy(chksum, 0, data, page+22, 4);
+        // Bad checksum. Lose sync */
+
+        headerbytes=0;
+        bodybytes=0;
+        // search for possible capture
+        next=0;
+        for(int ii=0; ii<bytes-1; ii++){
+          if(data[page+1+ii]=='O'){
+            next=page+1+ii;
+            break;
+          }
+        }
+        //next=memchr(page+1,'O',bytes-1);
+        if(next==0)
+          next=fill;
+        returned=next;
+        return (-(next-page));
+      }
+    //}
+
+    // yes, have a whole page all ready to go
+    {
+      page=returned;
+
+      if(og!=null){
+        og.header_base=data;
+        og.header=page;
+        og.header_len=headerbytes;
+        og.body_base=data;
+        og.body=page+headerbytes;
+        og.body_len=bodybytes;
+      }
+
+      unsynced=0;
+      returned+=(bytes=headerbytes+bodybytes);
+      headerbytes=0;
+      bodybytes=0;
+      return (bytes);
+    }
+  }
+
+  // sync the stream and get a page.  Keep trying until we find a page.
+  // Supress 'sync errors' after reporting the first.
+  //
+  // return values:
+  //  -1) recapture (hole in data)
+  //   0) need more data
+  //   1) page returned
+  //
+  // Returns pointers into buffered data; invalidated by next call to
+  // _stream, _clear, _init, or _buffer
+
+  public int pageout(Page og){
+    // all we need to do is verify a page at the head of the stream
+    // buffer.  If it doesn't verify, we look for the next potential
+    // frame
+
+    while(true){
+      int ret=pageseek(og);
+      if(ret>0){
+        // have a page
+        return (1);
+      }
+      if(ret==0){
+        // need more data
+        return (0);
+      }
+
+      // head did not start a synced page... skipped some bytes
+      if(unsynced==0){
+        unsynced=1;
+        return (-1);
+      }
+      // loop. keep looking
+    }
+  }
+
+  // clear things to an initial state.  Good to call, eg, before seeking
+  public int reset(){
+    fill=0;
+    returned=0;
+    unsynced=0;
+    headerbytes=0;
+    bodybytes=0;
+    return (0);
+  }
+
+  public void init(){
+  }
+
+  public int getDataOffset(){
+    return returned;
+  }
+
+  public int getBufferOffset(){
+    return fill;
+  }
+}



More information about the commits mailing list