package org.jcodec.containers.mp4.demuxer;

import static org.jcodec.common.Fourcc.free;
import static org.jcodec.common.Fourcc.ftyp;
import static org.jcodec.common.Fourcc.mdat;
import static org.jcodec.common.Fourcc.moov;
import static org.jcodec.common.Fourcc.wide;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.jcodec.common.Demuxer;
import org.jcodec.common.DemuxerTrack;
import org.jcodec.common.UsedViaReflection;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.io.SeekableByteChannel;
import org.jcodec.containers.mp4.MP4TrackType;
import org.jcodec.containers.mp4.MP4Util;
import org.jcodec.containers.mp4.MP4Util.Movie;
import org.jcodec.containers.mp4.boxes.Box;
import org.jcodec.containers.mp4.boxes.HandlerBox;
import org.jcodec.containers.mp4.boxes.MovieBox;
import org.jcodec.containers.mp4.boxes.NodeBox;
import org.jcodec.containers.mp4.boxes.SampleEntry;
import org.jcodec.containers.mp4.boxes.SampleSizesBox;
import org.jcodec.containers.mp4.boxes.TrakBox;
import org.jcodec.platform.Platform;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 *
 * Demuxer frontend for MP4
 *
 * @author The JCodec project
 *
 */
public class MP4Demuxer implements Demuxer {

    private List<AbstractMP4DemuxerTrack> tracks;
    private TimecodeMP4DemuxerTrack timecodeTrack;
    MovieBox movie;
    protected SeekableByteChannel input;

    //modifies h264 to conform to annexb and aac to contain adts header
    public static MP4Demuxer createMP4Demuxer(SeekableByteChannel input) throws IOException {
        return new MP4Demuxer(input);
    }

    //does not modify packets
    public static MP4Demuxer createRawMP4Demuxer(SeekableByteChannel input) throws IOException {
        return new MP4Demuxer(input) {
            @Override
            protected AbstractMP4DemuxerTrack newTrack(TrakBox trak) {
                return new MP4DemuxerTrack(movie, trak, this.input);
            }
        };
    }

    private AbstractMP4DemuxerTrack fromTrakBox(TrakBox trak) {
        SampleSizesBox stsz = NodeBox.findFirstPath(trak, SampleSizesBox.class, Box.path("mdia.minf.stbl.stsz"));
        if (stsz.getDefaultSize() == 0)
            return newTrack(trak);
        return new PCMMP4DemuxerTrack(movie, trak, input);
    }

    protected AbstractMP4DemuxerTrack newTrack(TrakBox trak) {
        return new CodecMP4DemuxerTrack(movie, trak, input);
    }

    MP4Demuxer(SeekableByteChannel input) throws IOException {
        this.input = input;
        tracks = new LinkedList<AbstractMP4DemuxerTrack>();
        findMovieBox(input);
    }

    private void findMovieBox(SeekableByteChannel input) throws IOException {
        Movie mv = MP4Util.parseFullMovieChannel(input);
        if (mv == null || mv.getMoov() == null)
            throw new IOException("Could not find movie meta information box");
        movie = mv.getMoov();

        processHeader(movie);
    }

    private void processHeader(NodeBox moov) throws IOException {
        TrakBox tt = null;
        TrakBox[] trakBoxs = NodeBox.findAll(moov, TrakBox.class, "trak");
        for (int i = 0; i < trakBoxs.length; i++) {
            TrakBox trak = trakBoxs[i];
            SampleEntry se = NodeBox.findFirstPath(trak, SampleEntry.class, new String[] { "mdia", "minf", "stbl", "stsd", null });
            if (se != null && "tmcd".equals(se.getFourcc())) {
                tt = trak;
            } else {
                tracks.add(fromTrakBox(trak));
            }
        }
        if (tt != null) {
            DemuxerTrack video = getVideoTrack();
            if (video != null)
                timecodeTrack = new TimecodeMP4DemuxerTrack(movie, tt, input);
        }
    }

    public static MP4TrackType getTrackType(TrakBox trak) {
        HandlerBox handler = NodeBox.findFirstPath(trak, HandlerBox.class, Box.path("mdia.hdlr"));
        return MP4TrackType.fromHandler(handler.getComponentSubType());
    }

    public DemuxerTrack getVideoTrack() {
        for (AbstractMP4DemuxerTrack demuxerTrack : tracks) {
            if (demuxerTrack.box.isVideo())
                return demuxerTrack;
        }
        return null;
    }

    public MovieBox getMovie() {
        return movie;
    }

    public AbstractMP4DemuxerTrack getTrack(int no) {
        for (AbstractMP4DemuxerTrack track : tracks) {
            if (track.getNo() == no)
                return track;
        }
        return null;
    }

    @Override
    public List<AbstractMP4DemuxerTrack> getTracks() {
        return new ArrayList<AbstractMP4DemuxerTrack>(tracks);
    }

    @Override
    public List<DemuxerTrack> getVideoTracks() {
        ArrayList<DemuxerTrack> result = new ArrayList<DemuxerTrack>();
        for (AbstractMP4DemuxerTrack demuxerTrack : tracks) {
            if (demuxerTrack.box.isVideo())
                result.add(demuxerTrack);
        }
        return result;
    }

    @Override
    public List<DemuxerTrack> getAudioTracks() {
        ArrayList<DemuxerTrack> result = new ArrayList<DemuxerTrack>();
        for (AbstractMP4DemuxerTrack demuxerTrack : tracks) {
            if (demuxerTrack.box.isAudio())
                result.add(demuxerTrack);
        }
        return result;
    }

    public TimecodeMP4DemuxerTrack getTimecodeTrack() {
        return timecodeTrack;
    }

    @UsedViaReflection
    public static int probe(final ByteBuffer b) {
        ByteBuffer fork = b.duplicate();
        int success = 0;
        int total = 0;
        while (fork.remaining() >= 8) {
            long len = Platform.unsignedInt(fork.getInt());
            int fcc = fork.getInt();
            int hdrLen = 8;
            if (len == 1) {
                len = fork.getLong();
                hdrLen = 16;
            } else if (len < 8)
                break;
            if (fcc == ftyp && len < 64 || fcc == moov && len < 100 * 1024 * 1024 || fcc == free || fcc == mdat
                    || fcc == wide)
                success++;
            total++;
            if (len >= Integer.MAX_VALUE)
                break;
            NIOUtils.skip(fork, (int) (len - hdrLen));
        }

        return total == 0 ? 0 : success * 100 / total;
    }

    @Override
    public void close() throws IOException {
        input.close();
    }
}


package net.sourceforge.jaad.aac.filterbank;

import net.sourceforge.jaad.aac.AACException;
import net.sourceforge.jaad.aac.syntax.SyntaxConstants;
import net.sourceforge.jaad.aac.syntax.ICSInfo.WindowSequence;

/**
 * This class is part of JAAD ( jaadec.sourceforge.net ) that is distributed
 * under the Public Domain license. Code changes provided by the JCodec project
 * are distributed under FreeBSD license.
 *
 * @author in-somnia
 */
public class FilterBank implements SyntaxConstants, SineWindows, KBDWindows {

	private final float[][] LONG_WINDOWS;// = {SINE_LONG, KBD_LONG};
	private final float[][] SHORT_WINDOWS;// = {SINE_SHORT, KBD_SHORT};
	private final int length, shortLen, mid, trans;
	private final MDCT mdctShort, mdctLong;
	private final float[] buf;
	private final float[][] overlaps;

	public FilterBank(boolean smallFrames, int channels) throws AACException {
		if(smallFrames) {
			length = WINDOW_SMALL_LEN_LONG;
			shortLen = WINDOW_SMALL_LEN_SHORT;
			LONG_WINDOWS = new float[][]{SINE_960, KBD_960};
			SHORT_WINDOWS = new float[][]{SINE_120, KBD_120};
		}
		else {
			length = WINDOW_LEN_LONG;
			shortLen = WINDOW_LEN_SHORT;
			LONG_WINDOWS = new float[][]{SINE_1024, KBD_1024};
			SHORT_WINDOWS = new float[][]{SINE_128, KBD_128};
		}
		mid = (length-shortLen)/2;
		trans = shortLen/2;

		mdctShort = new MDCT(shortLen*2);
		mdctLong = new MDCT(length*2);

		overlaps = new float[channels][length];
		buf = new float[2*length];
	}

	public void process(WindowSequence windowSequence, int windowShape, int windowShapePrev, float[] _in, float[] out, int channel) {
		int i;
		float[] overlap = overlaps[channel];
		switch(windowSequence) {
			case ONLY_LONG_SEQUENCE:
				mdctLong.process(_in, 0, buf, 0);
				//add second half output of previous frame to windowed output of current frame
				for(i = 0; i<length; i++) {
					out[i] = overlap[i]+(buf[i]*LONG_WINDOWS[windowShapePrev][i]);
				}

				//window the second half and save as overlap for next frame
				for(i = 0; i<length; i++) {
					overlap[i] = buf[length+i]*LONG_WINDOWS[windowShape][length-1-i];
				}
				break;
			case LONG_START_SEQUENCE:
				mdctLong.process(_in, 0, buf, 0);
				//add second half output of previous frame to windowed output of current frame
				for(i = 0; i<length; i++) {
					out[i] = overlap[i]+(buf[i]*LONG_WINDOWS[windowShapePrev][i]);
				}

				//window the second half and save as overlap for next frame
				for(i = 0; i<mid; i++) {
					overlap[i] = buf[length+i];
				}
				for(i = 0; i<shortLen; i++) {
					overlap[mid+i] = buf[length+mid+i]*SHORT_WINDOWS[windowShape][shortLen-i-1];
				}
				for(i = 0; i<mid; i++) {
					overlap[mid+shortLen+i] = 0;
				}
				break;
			case EIGHT_SHORT_SEQUENCE:
				for(i = 0; i<8; i++) {
					mdctShort.process(_in, i*shortLen, buf, 2*i*shortLen);
				}

				//add second half output of previous frame to windowed output of current frame
				for(i = 0; i<mid; i++) {
					out[i] = overlap[i];
				}
				for(i = 0; i<shortLen; i++) {
					out[mid+i] = overlap[mid+i]+(buf[i]*SHORT_WINDOWS[windowShapePrev][i]);
					out[mid+1*shortLen+i] = overlap[mid+shortLen*1+i]+(buf[shortLen*1+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*2+i]*SHORT_WINDOWS[windowShape][i]);
					out[mid+2*shortLen+i] = overlap[mid+shortLen*2+i]+(buf[shortLen*3+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*4+i]*SHORT_WINDOWS[windowShape][i]);
					out[mid+3*shortLen+i] = overlap[mid+shortLen*3+i]+(buf[shortLen*5+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*6+i]*SHORT_WINDOWS[windowShape][i]);
					if(i<trans) out[mid+4*shortLen+i] = overlap[mid+shortLen*4+i]+(buf[shortLen*7+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*8+i]*SHORT_WINDOWS[windowShape][i]);
				}

				//window the second half and save as overlap for next frame
				for(i = 0; i<shortLen; i++) {
					if(i>=trans) overlap[mid+4*shortLen+i-length] = (buf[shortLen*7+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*8+i]*SHORT_WINDOWS[windowShape][i]);
					overlap[mid+5*shortLen+i-length] = (buf[shortLen*9+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*10+i]*SHORT_WINDOWS[windowShape][i]);
					overlap[mid+6*shortLen+i-length] = (buf[shortLen*11+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*12+i]*SHORT_WINDOWS[windowShape][i]);
					overlap[mid+7*shortLen+i-length] = (buf[shortLen*13+i]*SHORT_WINDOWS[windowShape][shortLen-1-i])+(buf[shortLen*14+i]*SHORT_WINDOWS[windowShape][i]);
					overlap[mid+8*shortLen+i-length] = (buf[shortLen*15+i]*SHORT_WINDOWS[windowShape][shortLen-1-i]);
				}
				for(i = 0; i<mid; i++) {
					overlap[mid+shortLen+i] = 0;
				}
				break;
			case LONG_STOP_SEQUENCE:
				mdctLong.process(_in, 0, buf, 0);
				//add second half output of previous frame to windowed output of current frame
				//construct first half window using padding with 1's and 0's
				for(i = 0; i<mid; i++) {
					out[i] = overlap[i];
				}
				for(i = 0; i<shortLen; i++) {
					out[mid+i] = overlap[mid+i]+(buf[mid+i]*SHORT_WINDOWS[windowShapePrev][i]);
				}
				for(i = 0; i<mid; i++) {
					out[mid+shortLen+i] = overlap[mid+shortLen+i]+buf[mid+shortLen+i];
				}
				//window the second half and save as overlap for next frame
				for(i = 0; i<length; i++) {
					overlap[i] = buf[length+i]*LONG_WINDOWS[windowShape][length-1-i];
				}
				break;
		}
	}

	//only for LTP: no overlapping, no short blocks
	public void processLTP(WindowSequence windowSequence, int windowShape, int windowShapePrev, float[] _in, float[] out) {
		int i;

		switch(windowSequence) {
			case ONLY_LONG_SEQUENCE:
				for(i = length-1; i>=0; i--) {
					buf[i] = _in[i]*LONG_WINDOWS[windowShapePrev][i];
					buf[i+length] = _in[i+length]*LONG_WINDOWS[windowShape][length-1-i];
				}
				break;

			case LONG_START_SEQUENCE:
				for(i = 0; i<length; i++) {
					buf[i] = _in[i]*LONG_WINDOWS[windowShapePrev][i];
				}
				for(i = 0; i<mid; i++) {
					buf[i+length] = _in[i+length];
				}
				for(i = 0; i<shortLen; i++) {
					buf[i+length+mid] = _in[i+length+mid]*SHORT_WINDOWS[windowShape][shortLen-1-i];
				}
				for(i = 0; i<mid; i++) {
					buf[i+length+mid+shortLen] = 0;
				}
				break;

			case LONG_STOP_SEQUENCE:
				for(i = 0; i<mid; i++) {
					buf[i] = 0;
				}
				for(i = 0; i<shortLen; i++) {
					buf[i+mid] = _in[i+mid]*SHORT_WINDOWS[windowShapePrev][i];
				}
				for(i = 0; i<mid; i++) {
					buf[i+mid+shortLen] = _in[i+mid+shortLen];
				}
				for(i = 0; i<length; i++) {
					buf[i+length] = _in[i+length]*LONG_WINDOWS[windowShape][length-1-i];
				}
				break;
		}
		mdctLong.processForward(buf, out);
	}

	public float[] getOverlap(int channel) {
		return overlaps[channel];
	}
}


package net.sourceforge.jaad.aac.syntax;
import static java.lang.System.arraycopy;

import net.sourceforge.jaad.aac.AACException;

/**
 * This class is part of JAAD ( jaadec.sourceforge.net ) that is distributed
 * under the Public Domain license. Code changes provided by the JCodec project
 * are distributed under FreeBSD license.
 *
 * @author in-somnia
 */
public class BitStream implements IBitStream {

	private static final int WORD_BITS = 32;
	private static final int WORD_BYTES = 4;
	private static final int BYTE_MASK = 0xff;

	public static BitStream createBitStream(byte[] data) {
        BitStream bs = new BitStream();
        bs.setData(data);
        return bs;
    }

    private byte[] buffer;
	private int pos; //offset in the buffer array
	private int cache; //current 4 bytes, that are read from the buffer
	protected int bitsCached; //remaining bits in current cache
	protected int position; //number of total bits read

	public BitStream() {
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#destroy()
     */
	@Override
    public void destroy() {
		reset();
		buffer = null;
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#setData(byte[])
     */
	@Override
    public final void setData(byte[] data) {
		//make the buffer size an integer number of words
		final int size = WORD_BYTES*((data.length+WORD_BYTES-1)/WORD_BYTES);
		//only reallocate if needed
		if(buffer==null||buffer.length!=size) buffer = new byte[size];
		arraycopy(data, 0, buffer, 0, data.length);
		reset();
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#byteAlign()
     */
	@Override
    public void byteAlign() throws AACException {
		final int toFlush = bitsCached&7;
		if(toFlush>0) skipBits(toFlush);
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#reset()
     */
	@Override
    public final void reset() {
		pos = 0;
		bitsCached = 0;
		cache = 0;
		position = 0;
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#getPosition()
     */
	@Override
    public int getPosition() {
		return position;
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#getBitsLeft()
     */
	@Override
    public int getBitsLeft() {
		return buffer != null ? 8*(buffer.length-pos)+bitsCached : 0;
	}

	/**
	 * Reads the next four bytes.
	 * @param peek if true, the stream pointer will not be increased
	 */
	protected int readCache(boolean peek) throws AACException {
		int i;
		if(pos>buffer.length-WORD_BYTES) throw AACException.endOfStream();
		else i = ((buffer[pos]&BYTE_MASK)<<24)
					|((buffer[pos+1]&BYTE_MASK)<<16)
					|((buffer[pos+2]&BYTE_MASK)<<8)
					|(buffer[pos+3]&BYTE_MASK);
		if(!peek) pos += WORD_BYTES;
		return i;
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#readBits(int)
     */
	@Override
    public int readBits(int n) throws AACException {
		int result;
		if(bitsCached>=n) {
			bitsCached -= n;
			result = (cache>>bitsCached)&maskBits(n);
			position += n;
		}
		else {
			position += n;
			final int c = cache&maskBits(bitsCached);
			final int left = n-bitsCached;
			cache = readCache(false);
			bitsCached = WORD_BITS-left;
			result = ((cache>>bitsCached)&maskBits(left))|(c<<left);
		}
		return result;
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#readBit()
     */
	@Override
    public int readBit() throws AACException {
		int i;
		if(bitsCached>0) {
			bitsCached--;
			i = (cache>>(bitsCached))&1;
			position++;
		}
		else {
			cache = readCache(false);
			bitsCached = WORD_BITS-1;
			position++;
			i = (cache>>bitsCached)&1;
		}
		return i;
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#readBool()
     */
	@Override
    public boolean readBool() throws AACException {
		return (readBit()&0x1)!=0;
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#peekBits(int)
     */
	@Override
    public int peekBits(int n) throws AACException {
		int ret;
		if(bitsCached>=n) {
			ret = (cache>>(bitsCached-n))&maskBits(n);
		}
		else {
			//old cache
			final int c = cache&maskBits(bitsCached);
			n -= bitsCached;
			//read next & combine
			ret = ((readCache(true)>>WORD_BITS-n)&maskBits(n))|(c<<n);
		}
		return ret;
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#peekBit()
     */
	@Override
    public int peekBit() throws AACException {
		int ret;
		if(bitsCached>0) {
			ret = (cache>>(bitsCached-1))&1;
		}
		else {
			final int word = readCache(true);
			ret = (word>>WORD_BITS-1)&1;
		}
		return ret;
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#skipBits(int)
     */
	@Override
    public void skipBits(int n) throws AACException {
		position += n;
		if(n<=bitsCached) {
			bitsCached -= n;
		}
		else {
			n -= bitsCached;
			while(n>=WORD_BITS) {
				n -= WORD_BITS;
				readCache(false);
			}
			if(n>0) {
				cache = readCache(false);
				bitsCached = WORD_BITS-n;
			}
			else {
				cache = 0;
				bitsCached = 0;
			}
		}
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#skipBit()
     */
	@Override
    public void skipBit() throws AACException {
		position++;
		if(bitsCached>0) {
			bitsCached--;
		}
		else {
			cache = readCache(false);
			bitsCached = WORD_BITS-1;
		}
	}

	/* (non-Javadoc)
     * @see net.sourceforge.jaad.aac.syntax.IBitStream#maskBits(int)
     */
	@Override
    public int maskBits(int n) {
		int i;
		if(n==32) i = -1;
		else i = (1<<n)-1;
		return i;
	}
}


package org.jcodec.codecs.h264.io.model;

import java.util.Comparator;

import org.jcodec.codecs.h264.H264Utils.MvList2D;
import org.jcodec.common.model.ColorSpace;
import org.jcodec.common.model.Picture;
import org.jcodec.common.model.Rect;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 *
 * Picture extension with frame number, makes it easier to debug reordering
 *
 * @author The JCodec project
 *
 */
public class Frame extends Picture {
    private int frameNo;
    private SliceType frameType;
    private MvList2D mvs;
    private Frame[][][] refsUsed;
    private boolean shortTerm;
    private int poc;

    public Frame(int width, int height, byte[][] data, ColorSpace color, Rect crop, int frameNo, SliceType frameType,
            MvList2D mvs, Frame[][][] refsUsed, int poc) {
        super(width, height, data, null, color, 0, crop);
        this.frameNo = frameNo;
        this.mvs = mvs;
        this.refsUsed = refsUsed;
        this.poc = poc;
        shortTerm = true;
    }

    public static Frame createFrame(Frame pic) {
        Picture comp = pic.createCompatible();
        return new Frame(comp.getWidth(), comp.getHeight(), comp.getData(), comp.getColor(), pic.getCrop(),
                pic.frameNo, pic.frameType, pic.mvs, pic.refsUsed, pic.poc);
    }

    public Frame cropped() {
        Picture cropped = super.cropped();
        return new Frame(cropped.getWidth(), cropped.getHeight(), cropped.getData(), cropped.getColor(), null, frameNo,
                frameType, mvs, refsUsed, poc);
    }

    public void copyFromFrame(Frame src) {
        super.copyFrom(src);
        this.frameNo = src.frameNo;
        this.mvs = src.mvs;
        this.shortTerm = src.shortTerm;
        this.refsUsed = src.refsUsed;
        this.poc = src.poc;
    }

    /**
     * Creates a cropped clone of this picture.
     *
     * @return
     */
    public Frame cloneCropped() {
        if (cropNeeded()) {
            return cropped();
        } else {
            Frame clone = createFrame(this);
            clone.copyFrom(this);
            return clone;
        }
    }

    public int getFrameNo() {
        return frameNo;
    }

    public MvList2D getMvs() {
        return mvs;
    }

    public boolean isShortTerm() {
        return shortTerm;
    }

    public void setShortTerm(boolean shortTerm) {
        this.shortTerm = shortTerm;
    }

    public int getPOC() {
        return poc;
    }

    public static Comparator<Frame> POCAsc = new Comparator<Frame>() {
        public int compare(Frame o1, Frame o2) {
            if (o1 == null && o2 == null)
                return 0;
            else if (o1 == null)
                return 1;
            else if (o2 == null)
                return -1;
            else
                return o1.poc > o2.poc ? 1 : (o1.poc == o2.poc ? 0 : -1);
        }
    };

    public static Comparator<Frame> POCDesc = new Comparator<Frame>() {
        public int compare(Frame o1, Frame o2) {
            if (o1 == null && o2 == null)
                return 0;
            else if (o1 == null)
                return 1;
            else if (o2 == null)
                return -1;
            else
                return o1.poc < o2.poc ? 1 : (o1.poc == o2.poc ? 0 : -1);
        }
    };

    public Frame[][][] getRefsUsed() {
        return refsUsed;
    }

    public SliceType getFrameType() {
        return frameType;
    }
}


package net.sourceforge.jaad.aac.sbr;

/**
 * This class is part of JAAD ( jaadec.sourceforge.net ) that is distributed
 * under the Public Domain license. Code changes provided by the JCodec project
 * are distributed under FreeBSD license.
 *
 * @author in-somnia
 */
class DCT {

	private static final int n = 32;

	// w_array_real[i] = cos(2*M_PI*i/32)
	private static final float[] w_array_real = {
		1.000000000000000f, 0.980785279337272f,
		0.923879528329380f, 0.831469603195765f,
		0.707106765732237f, 0.555570210304169f,
		0.382683402077046f, 0.195090284503576f,
		0.000000000000000f, -0.195090370246552f,
		-0.382683482845162f, -0.555570282993553f,
		-0.707106827549476f, -0.831469651765257f,
		-0.923879561784627f, -0.980785296392607f
	};

	// w_array_imag[i] = sin(-2*M_PI*i/32)
	private static final float[] w_array_imag = {
		0.000000000000000f, -0.195090327375064f,
		-0.382683442461104f, -0.555570246648862f,
		-0.707106796640858f, -0.831469627480512f,
		-0.923879545057005f, -0.980785287864940f,
		-1.000000000000000f, -0.980785270809601f,
		-0.923879511601754f, -0.831469578911016f,
		-0.707106734823616f, -0.555570173959476f,
		-0.382683361692986f, -0.195090241632088f
	};

	private static final float[] dct4_64_tab = {
		0.999924719333649f, 0.998118102550507f,
		0.993906974792480f, 0.987301409244537f,
		0.978317379951477f, 0.966976463794708f,
		0.953306019306183f, 0.937339007854462f,
		0.919113874435425f, 0.898674488067627f,
		0.876070082187653f, 0.851355195045471f,
		0.824589252471924f, 0.795836925506592f,
		0.765167236328125f, 0.732654273509979f,
		0.698376238346100f, 0.662415742874146f,
		0.624859452247620f, 0.585797846317291f,
		0.545324981212616f, 0.503538429737091f,
		0.460538715124130f, 0.416429549455643f,
		0.371317148208618f, 0.325310230255127f,
		0.278519600629807f, 0.231058135628700f,
		0.183039888739586f, 0.134580686688423f,
		0.085797272622585f, 0.036807164549828f,
		-1.012196302413940f, -1.059438824653626f,
		-1.104129195213318f, -1.146159529685974f,
		-1.185428738594055f, -1.221842169761658f,
		-1.255311965942383f, -1.285757660865784f,
		-1.313105940818787f, -1.337290763854981f,
		-1.358253836631775f, -1.375944852828980f,
		-1.390321016311646f, -1.401347875595093f,
		-1.408998727798462f, -1.413255214691162f,
		-1.414107084274292f, -1.411552190780640f,
		-1.405596733093262f, -1.396255016326904f,
		-1.383549690246582f, -1.367511272430420f,
		-1.348178386688232f, -1.325597524642944f,
		-1.299823284149170f, -1.270917654037476f,
		-1.238950133323669f, -1.203998088836670f,
		-1.166145324707031f, -1.125483393669128f,
		-1.082109928131104f, -1.036129593849182f,
		-0.987653195858002f, -0.936797380447388f,
		-0.883684754371643f, -0.828443288803101f,
		-0.771206021308899f, -0.712110757827759f,
		-0.651300072669983f, -0.588920354843140f,
		-0.525121808052063f, -0.460058242082596f,
		-0.393886327743530f, -0.326765477657318f,
		-0.258857429027557f, -0.190325915813446f,
		-0.121335685253143f, -0.052053272724152f,
		0.017354607582092f, 0.086720645427704f,
		0.155877828598022f, 0.224659323692322f,
		0.292899727821350f, 0.360434412956238f,
		0.427100926637650f, 0.492738455533981f,
		0.557188928127289f, 0.620297133922577f,
		0.681910991668701f, 0.741881847381592f,
		0.800065577030182f, 0.856321990489960f,
		0.910515367984772f, 0.962515234947205f,
		1.000000000000000f, 0.998795449733734f,
		0.995184719562531f, 0.989176511764526f,
		0.980785250663757f, 0.970031261444092f,
		0.956940352916718f, 0.941544055938721f,
		0.923879504203796f, 0.903989315032959f,
		0.881921231746674f, 0.857728600502014f,
		0.831469595432281f, 0.803207516670227f,
		0.773010432720184f, 0.740951120853424f,
		0.707106769084930f, 0.671558916568756f,
		0.634393274784088f, 0.595699310302734f,
		0.555570185184479f, 0.514102697372437f,
		0.471396654844284f, 0.427555114030838f,
		0.382683426141739f, 0.336889833211899f,
		0.290284633636475f, 0.242980122566223f,
		0.195090234279633f, 0.146730497479439f,
		0.098017133772373f, 0.049067649990320f,
		-1.000000000000000f, -1.047863125801086f,
		-1.093201875686646f, -1.135906934738159f,
		-1.175875544548035f, -1.213011503219605f,
		-1.247225046157837f, -1.278433918952942f,
		-1.306562900543213f, -1.331544399261475f,
		-1.353317975997925f, -1.371831417083740f,
		-1.387039899826050f, -1.398906826972961f,
		-1.407403707504273f, -1.412510156631470f,
		0f, -1.412510156631470f,
		-1.407403707504273f, -1.398906826972961f,
		-1.387039899826050f, -1.371831417083740f,
		-1.353317975997925f, -1.331544399261475f,
		-1.306562900543213f, -1.278433918952942f,
		-1.247225046157837f, -1.213011384010315f,
		-1.175875544548035f, -1.135907053947449f,
		-1.093201875686646f, -1.047863125801086f,
		-1.000000000000000f, -0.949727773666382f,
		-0.897167563438416f, -0.842446029186249f,
		-0.785694956779480f, -0.727051079273224f,
		-0.666655659675598f, -0.604654192924500f,
		-0.541196048259735f, -0.476434230804443f,
		-0.410524487495422f, -0.343625843524933f,
		-0.275899350643158f, -0.207508206367493f,
		-0.138617098331451f, -0.069392144680023f,
		0f, 0.069392263889313f,
		0.138617157936096f, 0.207508206367493f,
		0.275899469852448f, 0.343625962734222f,
		0.410524636507034f, 0.476434201002121f,
		0.541196107864380f, 0.604654192924500f,
		0.666655719280243f, 0.727051138877869f,
		0.785695075988770f, 0.842446029186249f,
		0.897167563438416f, 0.949727773666382f
	};

	private static final int[] bit_rev_tab = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31};

	// FFT decimation in frequency
	// 4*16*2+16=128+16=144 multiplications
	// 6*16*2+10*8+4*16*2=192+80+128=400 additions
	private static void fft_dif(float[] Real, float[] Imag) {
		float w_real, w_imag; // For faster access
		float point1_real, point1_imag, point2_real, point2_imag; // For faster access
		int j, i, i2, w_index; // Counters

		// First 2 stages of 32 point FFT decimation in frequency
		// 4*16*2=64*2=128 multiplications
		// 6*16*2=96*2=192 additions
		// Stage 1 of 32 point FFT decimation in frequency
		for(i = 0; i<16; i++) {
			point1_real = Real[i];
			point1_imag = Imag[i];
			i2 = i+16;
			point2_real = Real[i2];
			point2_imag = Imag[i2];

			w_real = w_array_real[i];
			w_imag = w_array_imag[i];

			// temp1 = x[i] - x[i2]
			point1_real -= point2_real;
			point1_imag -= point2_imag;

			// x[i1] = x[i] + x[i2]
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// x[i2] = (x[i] - x[i2]) * w
			Real[i2] = ((point1_real*w_real)-(point1_imag*w_imag));
			Imag[i2] = ((point1_real*w_imag)+(point1_imag*w_real));
		}
		// Stage 2 of 32 point FFT decimation in frequency
		for(j = 0, w_index = 0; j<8; j++, w_index += 2) {
			w_real = w_array_real[w_index];
			w_imag = w_array_imag[w_index];

			i = j;
			point1_real = Real[i];
			point1_imag = Imag[i];
			i2 = i+8;
			point2_real = Real[i2];
			point2_imag = Imag[i2];

			// temp1 = x[i] - x[i2]
			point1_real -= point2_real;
			point1_imag -= point2_imag;

			// x[i1] = x[i] + x[i2]
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// x[i2] = (x[i] - x[i2]) * w
			Real[i2] = ((point1_real*w_real)-(point1_imag*w_imag));
			Imag[i2] = ((point1_real*w_imag)+(point1_imag*w_real));

			i = j+16;
			point1_real = Real[i];
			point1_imag = Imag[i];
			i2 = i+8;
			point2_real = Real[i2];
			point2_imag = Imag[i2];

			// temp1 = x[i] - x[i2]
			point1_real -= point2_real;
			point1_imag -= point2_imag;

			// x[i1] = x[i] + x[i2]
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// x[i2] = (x[i] - x[i2]) * w
			Real[i2] = ((point1_real*w_real)-(point1_imag*w_imag));
			Imag[i2] = ((point1_real*w_imag)+(point1_imag*w_real));
		}

		// Stage 3 of 32 point FFT decimation in frequency
		// 2*4*2=16 multiplications
		// 4*4*2+6*4*2=10*8=80 additions
		for(i = 0; i<n; i += 8) {
			i2 = i+4;
			point1_real = Real[i];
			point1_imag = Imag[i];

			point2_real = Real[i2];
			point2_imag = Imag[i2];

			// out[i1] = point1 + point2
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// out[i2] = point1 - point2
			Real[i2] = point1_real-point2_real;
			Imag[i2] = point1_imag-point2_imag;
		}
		w_real = w_array_real[4]; // = sqrt(2)/2
		// w_imag = -w_real; // = w_array_imag[4]; // = -sqrt(2)/2
		for(i = 1; i<n; i += 8) {
			i2 = i+4;
			point1_real = Real[i];
			point1_imag = Imag[i];

			point2_real = Real[i2];
			point2_imag = Imag[i2];

			// temp1 = x[i] - x[i2]
			point1_real -= point2_real;
			point1_imag -= point2_imag;

			// x[i1] = x[i] + x[i2]
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// x[i2] = (x[i] - x[i2]) * w
			Real[i2] = (point1_real+point1_imag)*w_real;
			Imag[i2] = (point1_imag-point1_real)*w_real;
		}
		for(i = 2; i<n; i += 8) {
			i2 = i+4;
			point1_real = Real[i];
			point1_imag = Imag[i];

			point2_real = Real[i2];
			point2_imag = Imag[i2];

			// x[i] = x[i] + x[i2]
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// x[i2] = (x[i] - x[i2]) * (-i)
			Real[i2] = point1_imag-point2_imag;
			Imag[i2] = point2_real-point1_real;
		}
		w_real = w_array_real[12]; // = -sqrt(2)/2
		// w_imag = w_real; // = w_array_imag[12]; // = -sqrt(2)/2
		for(i = 3; i<n; i += 8) {
			i2 = i+4;
			point1_real = Real[i];
			point1_imag = Imag[i];

			point2_real = Real[i2];
			point2_imag = Imag[i2];

			// temp1 = x[i] - x[i2]
			point1_real -= point2_real;
			point1_imag -= point2_imag;

			// x[i1] = x[i] + x[i2]
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// x[i2] = (x[i] - x[i2]) * w
			Real[i2] = (point1_real-point1_imag)*w_real;
			Imag[i2] = (point1_real+point1_imag)*w_real;
		}

		// Stage 4 of 32 point FFT decimation in frequency (no multiplications)
		// 16*4=64 additions
		for(i = 0; i<n; i += 4) {
			i2 = i+2;
			point1_real = Real[i];
			point1_imag = Imag[i];

			point2_real = Real[i2];
			point2_imag = Imag[i2];

			// x[i1] = x[i] + x[i2]
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// x[i2] = x[i] - x[i2]
			Real[i2] = point1_real-point2_real;
			Imag[i2] = point1_imag-point2_imag;
		}
		for(i = 1; i<n; i += 4) {
			i2 = i+2;
			point1_real = Real[i];
			point1_imag = Imag[i];

			point2_real = Real[i2];
			point2_imag = Imag[i2];

			// x[i] = x[i] + x[i2]
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// x[i2] = (x[i] - x[i2]) * (-i)
			Real[i2] = point1_imag-point2_imag;
			Imag[i2] = point2_real-point1_real;
		}

		// Stage 5 of 32 point FFT decimation in frequency (no multiplications)
		// 16*4=64 additions
		for(i = 0; i<n; i += 2) {
			i2 = i+1;
			point1_real = Real[i];
			point1_imag = Imag[i];

			point2_real = Real[i2];
			point2_imag = Imag[i2];

			// out[i1] = point1 + point2
			Real[i] += point2_real;
			Imag[i] += point2_imag;

			// out[i2] = point1 - point2
			Real[i2] = point1_real-point2_real;
			Imag[i2] = point1_imag-point2_imag;
		}

		//FFTReorder(Real, Imag);
	}

	/* size 64 only! */
	public static void dct4_kernel(float[] in_real, float[] in_imag, float[] out_real, float[] out_imag) {
		// Tables with bit reverse values for 5 bits, bit reverse of i at i-th position
		int i, i_rev;

		/* Step 2: modulate */
		// 3*32=96 multiplications
		// 3*32=96 additions
		for(i = 0; i<32; i++) {
			float x_re, x_im, tmp;
			x_re = in_real[i];
			x_im = in_imag[i];
			tmp = (x_re+x_im)*dct4_64_tab[i];
			in_real[i] = (x_im*dct4_64_tab[i+64])+tmp;
			in_imag[i] = (x_re*dct4_64_tab[i+32])+tmp;
		}

		/* Step 3: FFT, but with output in bit reverse order */
		fft_dif(in_real, in_imag);

		/* Step 4: modulate + bitreverse reordering */
		// 3*31+2=95 multiplications
		// 3*31+2=95 additions
		for(i = 0; i<16; i++) {
			float x_re, x_im, tmp;
			i_rev = bit_rev_tab[i];
			x_re = in_real[i_rev];
			x_im = in_imag[i_rev];

			tmp = (x_re+x_im)*dct4_64_tab[i+3*32];
			out_real[i] = (x_im*dct4_64_tab[i+5*32])+tmp;
			out_imag[i] = (x_re*dct4_64_tab[i+4*32])+tmp;
		}
		// i = 16, i_rev = 1 = rev(16);
		out_imag[16] = (in_imag[1]-in_real[1])*dct4_64_tab[16+3*32];
		out_real[16] = (in_real[1]+in_imag[1])*dct4_64_tab[16+3*32];
		for(i = 17; i<32; i++) {
			float x_re, x_im, tmp;
			i_rev = bit_rev_tab[i];
			x_re = in_real[i_rev];
			x_im = in_imag[i_rev];
			tmp = (x_re+x_im)*dct4_64_tab[i+3*32];
			out_real[i] = (x_im*dct4_64_tab[i+5*32])+tmp;
			out_imag[i] = (x_re*dct4_64_tab[i+4*32])+tmp;
		}

	}
}


package org.jcodec.codecs.wav;
import org.jcodec.api.UnhandledStateException;
import org.jcodec.common.AudioFormat;
import org.jcodec.common.JCodecUtil2;
import org.jcodec.common.io.IOUtils;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.model.ChannelLabel;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 *
 * @author The JCodec project
 *
 */
public class WavHeader {

    public static class FmtChunkExtended extends FmtChunk {
        short cbSize;
        short bitsPerCodedSample;
        int channelLayout;
        int guid;

        public FmtChunkExtended(FmtChunk other, short cbSize, short bitsPerCodedSample, int channelLayout, int guid) {
            super(other.audioFormat, other.numChannels, other.sampleRate, other.byteRate, other.blockAlign,
                    other.bitsPerSample);
            this.cbSize = cbSize;
            this.bitsPerCodedSample = bitsPerCodedSample;
            this.channelLayout = channelLayout;
            this.guid = guid;
        }

        public static FmtChunk read(ByteBuffer bb) throws IOException {
            FmtChunk fmtChunk = FmtChunk.get(bb);
            ByteOrder old = (ByteOrder) bb.order();
            try {
                bb.order(ByteOrder.LITTLE_ENDIAN);
                return new FmtChunkExtended(fmtChunk, bb.getShort(), bb.getShort(), bb.getInt(), bb.getInt());
            } finally {
                bb.order(old);
            }
        }

        public void put(ByteBuffer bb) throws IOException {
            super.put(bb);
            ByteOrder old = (ByteOrder) bb.order();
            bb.order(ByteOrder.LITTLE_ENDIAN);
            bb.putShort(cbSize);
            bb.putShort(bitsPerCodedSample);
            bb.putInt(channelLayout);
            bb.putInt(guid);
            bb.order(old);
        }

        public int size() {
            return super.size() + 12;
        }

        public ChannelLabel[] getLabels() {
            List<ChannelLabel> labels = new ArrayList<ChannelLabel>();
            for (int i = 0; i < mapping.length; i++) {
                if ((channelLayout & (1 << i)) != 0)
                    labels.add(mapping[i]);
            }
            return labels.toArray(new ChannelLabel[0]);
        }
    }

    static ChannelLabel[] mapping = new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT,
            ChannelLabel.CENTER, ChannelLabel.LFE, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT,
            ChannelLabel.FRONT_CENTER_LEFT, ChannelLabel.FRONT_CENTER_RIGHT, ChannelLabel.REAR_CENTER,
            ChannelLabel.SIDE_LEFT, ChannelLabel.SIDE_RIGHT, ChannelLabel.CENTER, ChannelLabel.FRONT_LEFT,
            ChannelLabel.CENTER, ChannelLabel.FRONT_RIGHT, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_CENTER,
            ChannelLabel.REAR_RIGHT, ChannelLabel.STEREO_LEFT, ChannelLabel.STEREO_RIGHT };

    public static class FmtChunk {
        public short audioFormat;
        public short numChannels;
        public int sampleRate;
        public int byteRate;
        public short blockAlign;
        public short bitsPerSample;

        public FmtChunk(short audioFormat, short numChannels, int sampleRate, int byteRate, short blockAlign,
                short bitsPerSample) {
            this.audioFormat = audioFormat;
            this.numChannels = numChannels;
            this.sampleRate = sampleRate;
            this.byteRate = byteRate;
            this.blockAlign = blockAlign;
            this.bitsPerSample = bitsPerSample;
        }

        public static FmtChunk get(ByteBuffer bb) throws IOException {
            ByteOrder old = (ByteOrder) bb.order();
            try {
                bb.order(ByteOrder.LITTLE_ENDIAN);
                return new FmtChunk(bb.getShort(), bb.getShort(), bb.getInt(), bb.getInt(), bb.getShort(),
                        bb.getShort());
            } finally {
                bb.order(old);
            }
        }

        public void put(ByteBuffer bb) throws IOException {
            ByteOrder old = (ByteOrder) bb.order();
            bb.order(ByteOrder.LITTLE_ENDIAN);
            bb.putShort(audioFormat);
            bb.putShort(numChannels);
            bb.putInt(sampleRate);
            bb.putInt(byteRate);
            bb.putShort(blockAlign);
            bb.putShort(bitsPerSample);
            bb.order(old);
        }

        public int size() {
            return 16;
        }
    }

    public String chunkId;
    public int chunkSize;
    public String format;
    public FmtChunk fmt;
    public int dataOffset;
    public long dataSize;
    public static final int WAV_HEADER_SIZE = 44;

    public WavHeader(String chunkId, int chunkSize, String format, FmtChunk fmt, int dataOffset, long dataSize) {
        this.chunkId = chunkId;
        this.chunkSize = chunkSize;
        this.format = format;
        this.fmt = fmt;
        this.dataOffset = dataOffset;
        this.dataSize = dataSize;
    }

    public static WavHeader copyWithRate(WavHeader header, int rate) {
        WavHeader result = new WavHeader(header.chunkId, header.chunkSize, header.format,
                copyFmt(header.fmt), header.dataOffset, header.dataSize);
        result.fmt.sampleRate = rate;
        return result;
    }

    public static WavHeader copyWithChannels(WavHeader header, int channels) {
        WavHeader result = new WavHeader(header.chunkId, header.chunkSize, header.format,
                copyFmt(header.fmt), header.dataOffset, header.dataSize);
        result.fmt.numChannels = (short) channels;
        return result;
    }

    private static FmtChunk copyFmt(FmtChunk fmt) {
        if (fmt instanceof FmtChunkExtended) {
            FmtChunkExtended fmtext = (FmtChunkExtended) fmt;
            fmt = new FmtChunkExtended(fmtext, fmtext.cbSize, fmtext.bitsPerCodedSample, fmtext.channelLayout, fmtext.guid);
        }        else {
            fmt = new FmtChunk(fmt.audioFormat, fmt.numChannels, fmt.sampleRate, fmt.byteRate, fmt.blockAlign,
                    fmt.bitsPerSample);
        }
        return fmt;
    }

    /**
     * Creates wav header for the specified audio format
     *
     * @param format
     * @param samples
     */
    public static WavHeader createWavHeader(AudioFormat format, int samples) {
        WavHeader w = new WavHeader("RIFF", 40, "WAVE", new FmtChunk((short) 1, (short) format.getChannels(), format.getSampleRate(),
                format.getSampleRate() * format.getChannels() * (format.getSampleSizeInBits() >> 3),
                (short) (format.getChannels() * (format.getSampleSizeInBits() >> 3)),
                (short) format.getSampleSizeInBits()), 44, calcDataSize(format.getChannels(),
                format.getSampleSizeInBits() >> 3, samples));
        return w;
    }

    public static WavHeader stereo48k() {
        return stereo48kWithSamples(0);
    }

    public static WavHeader stereo48kWithSamples(long samples) {
        return new WavHeader("RIFF", 40, "WAVE", new FmtChunk((short) 1, (short) 2, 48000, 48000 * 2 * 16 / 8,
                (short) 4, (short) 16), 44, calcDataSize(2, 2, samples));
    }

    public static WavHeader mono48k(long samples) {
        return new WavHeader("RIFF", 40, "WAVE", new FmtChunk((short) 1, (short) 1, 48000, 48000 * 1 * 16 / 8,
                (short) 2, (short) 16), 44, calcDataSize(1, 2, samples));
    }

    public static WavHeader emptyWavHeader() {
        return new WavHeader("RIFF", 40, "WAVE", newFmtChunk(), 44, 0);
    }

    private static FmtChunk newFmtChunk() {
        return new FmtChunk((short) 1, (short) 0, 0, 0, (short) 0, (short) 0);
    }

    public static WavHeader read(File file) throws IOException {
        ReadableByteChannel is = null;
        try {
            is = NIOUtils.readableChannel(file);
            return readChannel(is);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    public static WavHeader readChannel(ReadableByteChannel _in) throws IOException {
        ByteBuffer buf = ByteBuffer.allocate(128);
        buf.order(ByteOrder.LITTLE_ENDIAN);
        _in.read(buf);
        if (buf.remaining() > 0)
            throw new IOException("Incomplete wav header found");
        buf.flip();

        String chunkId = NIOUtils.readString(buf, 4);
        int chunkSize = buf.getInt();
        String format = NIOUtils.readString(buf, 4);
        FmtChunk fmt = null;

        if (!"RIFF".equals(chunkId) || !"WAVE".equals(format)) {
            return null;
        }
        String fourcc;
        int size = 0;
        do {
            fourcc = NIOUtils.readString(buf, 4);
            size = buf.getInt();
            if ("fmt ".equals(fourcc) && size >= 14 && size <= 1024 * 1024) {
                switch (size) {
                case 16:
                    fmt = FmtChunk.get(buf);
                    break;
                case 18:
                    fmt = FmtChunk.get(buf);
                    NIOUtils.skip(buf, 2);
                    break;
                case 40:
                    fmt = FmtChunkExtended.get(buf);
                    NIOUtils.skip(buf, 12);
                    break;
                case 28:
                    fmt = FmtChunkExtended.get(buf);
                    break;
                default:
                    throw new UnhandledStateException("Don't know how to handle fmt size: " + size);
                }
            } else if (!"data".equals(fourcc)) {
                NIOUtils.skip(buf, size);
            }
        } while (!"data".equals(fourcc));

        return new WavHeader(chunkId, chunkSize, format, fmt, buf.position(), size);
    }

    public static WavHeader multiChannelWavFromFiles(File[] files) throws IOException {
        WavHeader headers[] = new WavHeader[files.length];
        for (int i = 0; i < files.length; i++) {
            headers[i] = read(files[i]);
        }
        return multiChannelWav(headers);
    }

    /** Takes single channel wavs as input produces multi channel wav */
    public static WavHeader multiChannelWav(WavHeader[] headers) {
        WavHeader w = emptyWavHeader();
        int totalSize = 0;
        for (int i = 0; i < headers.length; i++) {
            WavHeader wavHeader = headers[i];
            totalSize += wavHeader.dataSize;
        }
        w.dataSize = totalSize;
        FmtChunk fmt = headers[0].fmt;
        int bitsPerSample = fmt.bitsPerSample;
        int bytesPerSample = bitsPerSample / 8;
        int sampleRate = (int) fmt.sampleRate;
        w.fmt.bitsPerSample = (short) bitsPerSample;
        w.fmt.blockAlign = (short) (headers.length * bytesPerSample);
        w.fmt.byteRate = headers.length * bytesPerSample * sampleRate;
        w.fmt.numChannels = (short) headers.length;
        w.fmt.sampleRate = sampleRate;
        return w;
    }

    public void write(WritableByteChannel out) throws IOException {
        ByteBuffer bb = ByteBuffer.allocate(44);
        bb.order(ByteOrder.LITTLE_ENDIAN);

        long chunkSize;
        if (dataSize <= 0xffffffffL) {
            chunkSize = dataSize + 36;
        } else {
            chunkSize = 40;
        }

        bb.put(JCodecUtil2.asciiString("RIFF"));
        bb.putInt((int) chunkSize);
        bb.put(JCodecUtil2.asciiString("WAVE"));

        bb.put(JCodecUtil2.asciiString("fmt "));
        bb.putInt(fmt.size());
        fmt.put(bb);
        bb.put(JCodecUtil2.asciiString("data"));
        if (dataSize <= 0xffffffffL) {
            bb.putInt((int) dataSize);
        } else {
            bb.putInt(0);
        }
        bb.flip();
        out.write(bb);
    }

    public static long calcDataSize(int numChannels, int bytesPerSample, long samples) {
        return samples * numChannels * bytesPerSample;
    }

    public static WavHeader create(AudioFormat af, int size) {
        WavHeader w = emptyWavHeader();
        w.dataSize = size;
        FmtChunk fmt = newFmtChunk();
        int bitsPerSample = af.getSampleSizeInBits();
        int bytesPerSample = bitsPerSample / 8;
        int sampleRate = (int) af.getSampleRate();
        w.fmt.bitsPerSample = (short) bitsPerSample;
        w.fmt.blockAlign = (short) (af.getFrameSize());
        w.fmt.byteRate = (int) af.getFrameRate() * af.getFrameSize();
        w.fmt.numChannels = (short) af.getChannels();
        w.fmt.sampleRate = (int) af.getSampleRate();
        return w;
    }

    public ChannelLabel[] getChannelLabels() {
        if (fmt instanceof FmtChunkExtended) {
            return ((FmtChunkExtended) fmt).getLabels();
        } else {
            switch (fmt.numChannels) {
            case 1:
                return new ChannelLabel[] { ChannelLabel.MONO };
            case 2:
                return new ChannelLabel[] { ChannelLabel.STEREO_LEFT, ChannelLabel.STEREO_RIGHT };
            case 3:
                return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.REAR_CENTER };
            case 4:
                return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.REAR_LEFT,
                        ChannelLabel.REAR_RIGHT };
            case 5:
                return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.CENTER,
                        ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT };
            case 6:
                return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.CENTER,
                        ChannelLabel.LFE, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT };
            case 7:
                return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.CENTER,
                        ChannelLabel.LFE, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT, ChannelLabel.REAR_CENTER };
            case 8:
                return new ChannelLabel[] { ChannelLabel.FRONT_LEFT, ChannelLabel.FRONT_RIGHT, ChannelLabel.CENTER,
                        ChannelLabel.LFE, ChannelLabel.REAR_LEFT, ChannelLabel.REAR_RIGHT, ChannelLabel.REAR_LEFT,
                        ChannelLabel.REAR_RIGHT };
            default:
                ChannelLabel[] labels = new ChannelLabel[fmt.numChannels];
                Arrays.fill(labels, ChannelLabel.MONO);
                return labels;
            }
        }
    }

    public AudioFormat getFormat() {
        return new AudioFormat(fmt.sampleRate, fmt.bitsPerSample, fmt.numChannels, true, false);
    }
}


package org.jcodec.common.io;
import java.io.IOException;
import java.io.InputStream;
import java.lang.IllegalArgumentException;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 *
 * A dummy implementation of H264 RBSP reading
 *
 * @author The JCodec project
 *
 */
public class DummyBitstreamReader {
    private InputStream is;
    private int curByte;
    private int nextByte;
    private int secondByte;
    int nBit;
    protected static int bitsRead;

    public DummyBitstreamReader(InputStream is) throws IOException {
        this.is = is;
        curByte = is.read();
        nextByte = is.read();
        secondByte = is.read();
        // println("\n-> " + curByte);
    }

    int cnt = 0;

    /*
     * (non-Javadoc)
     *
     * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#read1Bit()
     */
    public int read1Bit() throws IOException {
        return read1BitInt();
    }

    public int read1BitInt() throws IOException {

        if (nBit == 8) {
            advance();
            if (curByte == -1) {
                return -1;
            }
        }
        int res = (curByte >> (7 - nBit)) & 1;
        nBit++;

//        debugBits.append(res == 0 ? '0' : '1');
        ++bitsRead;

        return res;
    }

    /*
     * (non-Javadoc)
     *
     * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#readNBit(int)
     */
    public int readNBit(int n) throws IOException {
        if (n > 32)
            throw new IllegalArgumentException("Can not read more then 32 bit");

        int val = 0;

        for (int i = 0; i < n; i++) {
            val <<= 1;
            val |= read1BitInt();
        }

        return val;
    }

    private final void advance1() throws IOException {
        curByte = nextByte;
        nextByte = secondByte;
        secondByte = is.read();
    }

    private final void advance() throws IOException {
        advance1();
        nBit = 0;
        // println("\n-> " + curByte);
    }

    /*
     * (non-Javadoc)
     *
     * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#readByte()
     */
    public int readByte() throws IOException {
        if (nBit > 0) {
            advance();
        }

        int res = curByte;

        advance();

        return res;
    }

    /*
     * (non-Javadoc)
     *
     * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#moreRBSPData()
     */
    public boolean moreRBSPData() throws IOException {
        if (nBit == 8) {
            advance();
        }
        int tail = 1 << (8 - nBit - 1);
        int mask = ((tail << 1) - 1);
        boolean hasTail = (curByte & mask) == tail;

        return !(curByte == -1 || (nextByte == -1 && hasTail));
    }

    public long getBitPosition() {
        return (bitsRead * 8 + (nBit % 8));
    }

    public boolean moreData() throws IOException {
        if (nBit == 8)
            advance();
        if (curByte == -1)
            return false;
        if (nextByte == -1 || (nextByte == 0 && secondByte == -1)) {
            int mask = (1 << (8 - nBit)) - 1;
            return (curByte & mask) != 0;
        }
        return true;
    }

    /*
     * (non-Javadoc)
     *
     * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#readRemainingByte()
     */
    public long readRemainingByte() throws IOException {
        return readNBit(8 - nBit);
    }

    /*
     * (non-Javadoc)
     *
     * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#next_bits(int)
     */
    public int peakNextBits(int n) throws IOException {
        if (n > 8)
            throw new IllegalArgumentException("N should be less then 8");
        if (nBit == 8) {
            advance();
            if (curByte == -1) {
                return -1;
            }
        }
        int[] bits = new int[16 - nBit];

        int cnt = 0;
        for (int i = nBit; i < 8; i++) {
            bits[cnt++] = (curByte >> (7 - i)) & 0x1;
        }

        for (int i = 0; i < 8; i++) {
            bits[cnt++] = (nextByte >> (7 - i)) & 0x1;
        }

        int result = 0;
        for (int i = 0; i < n; i++) {
            result <<= 1;
            result |= bits[i];
        }

        return result;
    }

    /*
     * (non-Javadoc)
     *
     * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#byte_aligned()
     */
    public boolean isByteAligned() {
        return (nBit % 8) == 0;
    }

    /*
     * (non-Javadoc)
     *
     * @see ua.org.jplayer.javcodec.h264.RBSPInputStream#close()
     */
    public void close() throws IOException {
        is.close();
    }

    public int getCurBit() {
        return nBit;
    }

    public final int skip(int bits) throws IOException {
        nBit += bits;
        int was = nBit;
        while (nBit >= 8 && curByte != -1) {
            advance1();
            nBit -= 8;
        }
        return was - nBit;
    }

    public int align() throws IOException {
        int n = (8 - nBit) & 0x7;
        skip((8 - nBit) & 0x7);
        return n;
    }

    public int checkNBit(int n) throws IOException {
        return peakNextBits(n);
    }

    public int curBit() {
        return nBit;
    }

    public boolean lastByte() throws IOException {
        return nextByte == -1 && secondByte == -1;
    }
}


package org.jcodec.codecs.mpa;

import static org.jcodec.codecs.mpa.MpaConst.MPEG1;
import static org.jcodec.codecs.mpa.MpaConst.bigValEscBits;
import static org.jcodec.codecs.mpa.MpaConst.bigValMaxval;
import static org.jcodec.codecs.mpa.MpaConst.bigValVlc;
import static org.jcodec.codecs.mpa.MpaConst.scaleFactorLen;
import static org.jcodec.common.Vector2Int.el16_0;
import static org.jcodec.common.Vector2Int.el16_1;
import static org.jcodec.common.Vector4Int.el8_0;
import static org.jcodec.common.Vector4Int.el8_1;
import static org.jcodec.common.Vector4Int.el8_2;
import static org.jcodec.common.Vector4Int.el8_3;

import java.nio.ByteBuffer;

import org.jcodec.common.Vector2Int;
import org.jcodec.common.Vector4Int;
import org.jcodec.common.io.BitReader;
import org.jcodec.common.tools.MathUtil;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 *
 * @author The JCodec project
 */
public class Mp3Bitstream {

    static class MP3SideInfo {
        int mainDataBegin;
        int privateBits;
        boolean[][] scfsi;
        Granule[][] granule;

        MP3SideInfo() {
            scfsi = new boolean[2][4];
            granule = new Granule[][] {{new Granule(), new Granule()}, {new Granule(), new Granule()}};
        }
    }

    static class Granule {
        int part23Length;
        int bigValues;
        int globalGain;
        int scalefacCompress;
        boolean windowSwitchingFlag;
        int blockType;
        boolean mixedBlockFlag;
        int[] tableSelect;
        int[] subblockGain;
        int region0Count;
        int region1Count;
        boolean preflag;
        int scalefacScale;
        int count1tableSelect;

        Granule() {
            tableSelect = new int[3];
            subblockGain = new int[3];
        }
    }

    static class ScaleFactors {
        int[] large;
        int[][] small;

        ScaleFactors() {
            large = new int[23];
            small = new int[3][13];
        }
    }

    //Wrong usage of Javascript keyword:in
    static MP3SideInfo readSideInfo(MpaHeader header, ByteBuffer src, int channels) {
        MP3SideInfo si = new MP3SideInfo();
        BitReader stream = BitReader.createBitReader(src);
        if (header.version == MPEG1) {

            si.mainDataBegin = stream.readNBit(9);
            if (channels == 1)
                si.privateBits = stream.readNBit(5);
            else
                si.privateBits = stream.readNBit(3);

            for (int ch = 0; ch < channels; ch++) {
                si.scfsi[ch][0] = stream.read1Bit() == 0;
                si.scfsi[ch][1] = stream.read1Bit() == 0;
                si.scfsi[ch][2] = stream.read1Bit() == 0;
                si.scfsi[ch][3] = stream.read1Bit() == 0;
            }

            for (int gr = 0; gr < 2; gr++) {
                for (int ch = 0; ch < channels; ch++) {
                    Granule granule = si.granule[ch][gr];
                    granule.part23Length = stream.readNBit(12);
                    granule.bigValues = stream.readNBit(9);
                    granule.globalGain = stream.readNBit(8);
                    granule.scalefacCompress = stream.readNBit(4);
                    granule.windowSwitchingFlag = stream.readNBit(1) != 0;
                    if (granule.windowSwitchingFlag) {
                        granule.blockType = stream.readNBit(2);
                        granule.mixedBlockFlag = stream.readNBit(1) != 0;

                        granule.tableSelect[0] = stream.readNBit(5);
                        granule.tableSelect[1] = stream.readNBit(5);

                        granule.subblockGain[0] = stream.readNBit(3);
                        granule.subblockGain[1] = stream.readNBit(3);
                        granule.subblockGain[2] = stream.readNBit(3);

                        if (granule.blockType == 0) {
                            return null;
                        } else if (granule.blockType == 2 && !granule.mixedBlockFlag) {
                            granule.region0Count = 8;
                        } else {
                            granule.region0Count = 7;
                        }
                        granule.region1Count = 20 - granule.region0Count;
                    } else {
                        granule.tableSelect[0] = stream.readNBit(5);
                        granule.tableSelect[1] = stream.readNBit(5);
                        granule.tableSelect[2] = stream.readNBit(5);
                        granule.region0Count = stream.readNBit(4);
                        granule.region1Count = stream.readNBit(3);
                        granule.blockType = 0;
                    }
                    granule.preflag = stream.readNBit(1) != 0;
                    granule.scalefacScale = stream.readNBit(1);
                    granule.count1tableSelect = stream.readNBit(1);
                }
            }

        } else {
            si.mainDataBegin = stream.readNBit(8);
            if (channels == 1)
                si.privateBits = stream.readNBit(1);
            else
                si.privateBits = stream.readNBit(2);

            for (int ch = 0; ch < channels; ch++) {
                Granule granule = si.granule[ch][0];
                granule.part23Length = stream.readNBit(12);
                granule.bigValues = stream.readNBit(9);
                granule.globalGain = stream.readNBit(8);
                granule.scalefacCompress = stream.readNBit(9);
                granule.windowSwitchingFlag = stream.readNBit(1) != 0;

                if (granule.windowSwitchingFlag) {

                    granule.blockType = stream.readNBit(2);
                    granule.mixedBlockFlag = stream.readNBit(1) != 0;
                    granule.tableSelect[0] = stream.readNBit(5);
                    granule.tableSelect[1] = stream.readNBit(5);

                    granule.subblockGain[0] = stream.readNBit(3);
                    granule.subblockGain[1] = stream.readNBit(3);
                    granule.subblockGain[2] = stream.readNBit(3);

                    if (granule.blockType == 0) {
                        return null;
                    } else if (granule.blockType == 2 && !granule.mixedBlockFlag) {
                        granule.region0Count = 8;
                    } else {
                        granule.region0Count = 7;
                        granule.region1Count = 20 - granule.region0Count;
                    }

                } else {
                    granule.tableSelect[0] = stream.readNBit(5);
                    granule.tableSelect[1] = stream.readNBit(5);
                    granule.tableSelect[2] = stream.readNBit(5);
                    granule.region0Count = stream.readNBit(4);
                    granule.region1Count = stream.readNBit(3);
                    granule.blockType = 0;
                }

                granule.scalefacScale = stream.readNBit(1);
                granule.count1tableSelect = stream.readNBit(1);
            }
        }
        stream.terminate();
        return si;
    }

    static ScaleFactors readScaleFactors(BitReader br, Granule granule, boolean[] b) {
        if (granule.windowSwitchingFlag && (granule.blockType == 2)) {
            if (granule.mixedBlockFlag) {
                return readScaleFacMixed(br, granule);
            } else {
                return readScaleFacShort(br, granule);
            }
        } else {
            return readScaleFacNonSwitch(br, granule, b);
        }
    }

    private static ScaleFactors readScaleFacMixed(BitReader br, Granule granule) {
        ScaleFactors sf = new ScaleFactors();
        for (int sfb = 0; sfb < 8; sfb++)
            sf.large[sfb] = br.readNBit(scaleFactorLen[0][granule.scalefacCompress]);
        for (int sfb = 3; sfb < 6; sfb++)
            for (int window = 0; window < 3; window++)
                sf.small[window][sfb] = br.readNBit(scaleFactorLen[0][granule.scalefacCompress]);
        for (int sfb = 6; sfb < 12; sfb++)
            for (int window = 0; window < 3; window++)
                sf.small[window][sfb] = br.readNBit(scaleFactorLen[1][granule.scalefacCompress]);
        for (int sfb = 12, window = 0; window < 3; window++)
            sf.small[window][sfb] = 0;
        return sf;
    }

    private static ScaleFactors readScaleFacNonSwitch(BitReader br, Granule granule, boolean[] b) {
        ScaleFactors sf = new ScaleFactors();
        int length0 = scaleFactorLen[0][granule.scalefacCompress];
        int length1 = scaleFactorLen[1][granule.scalefacCompress];
        if (b[0]) {
            for (int i = 0; i < 6; i++)
                sf.large[i] = br.readNBit(length0);
        }
        if (b[1]) {
            for (int i = 6; i < 11; i++)
                sf.large[i] = br.readNBit(length0);
        }
        if (b[2]) {
            for (int i = 11; i < 16; i++)
                sf.large[i] = br.readNBit(length1);
        }
        if (b[3]) {
            for (int i = 16; i < 21; i++)
                sf.large[i] = br.readNBit(length1);
        }
        sf.large[21] = 0;
        sf.large[22] = 0;
        return sf;
    }

    private static ScaleFactors readScaleFacShort(BitReader br, Granule granule) {
        ScaleFactors sf = new ScaleFactors();
        int length0 = scaleFactorLen[0][granule.scalefacCompress];
        int length1 = scaleFactorLen[1][granule.scalefacCompress];
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 3; j++)
                sf.small[j][i] = br.readNBit(length0);
        }
        for (int i = 6; i < 12; i++) {
            for (int j = 0; j < 3; j++)
                sf.small[j][i] = br.readNBit(length1);
        }
        sf.small[0][12] = 0;
        sf.small[1][12] = 0;
        sf.small[2][12] = 0;
        return sf;
    }

    static ScaleFactors readLSFScaleFactors(BitReader br, MpaHeader header, Granule granule, int ch) {
        ScaleFactors scalefac = new ScaleFactors();
        int[] scalefacBuffer = readLSFScaleData(br, header, granule, ch);

        int m = 0;
        if (granule.windowSwitchingFlag && granule.blockType == 2) {
            if (granule.mixedBlockFlag) {
                for (int sfb = 0; sfb < 8; sfb++) {
                    scalefac.large[sfb] = scalefacBuffer[m];
                    m++;
                }
                for (int sfb = 3; sfb < 12; sfb++) {
                    for (int window = 0; window < 3; window++) {
                        scalefac.small[window][sfb] = scalefacBuffer[m];
                        m++;
                    }
                }
                for (int window = 0; window < 3; window++)
                    scalefac.small[window][12] = 0;

            } else {
                for (int sfb = 0; sfb < 12; sfb++) {
                    for (int window = 0; window < 3; window++) {
                        scalefac.small[window][sfb] = scalefacBuffer[m];
                        m++;
                    }
                }

                for (int window = 0; window < 3; window++)
                    scalefac.small[window][12] = 0;
            }
        } else {

            for (int sfb = 0; sfb < 21; sfb++) {
                scalefac.large[sfb] = scalefacBuffer[m];
                m++;
            }
            scalefac.large[21] = 0;
            scalefac.large[22] = 0;
        }
        return scalefac;
    }

    private static int[] readLSFScaleData(BitReader br, MpaHeader header, Granule granule, int ch) {
        int[] result = new int[54];
        int[] scaleFacLen = new int[4];

        int comp = granule.scalefacCompress;

        int blockType = granule.blockType == 2 ? (granule.mixedBlockFlag ? 2 : 1) : 0;

        boolean ch1 = (header.modeExtension == 1 || header.modeExtension == 3) && (ch == 1);
        int lenType = 0;
        if (!ch1) {
            if (comp < 400) {
                scaleFacLen[0] = (comp >>> 4) / 5;
                scaleFacLen[1] = (comp >>> 4) % 5;
                scaleFacLen[2] = (comp & 0xF) >>> 2;
                scaleFacLen[3] = (comp & 3);
                granule.preflag = false;
                lenType = 0;
            } else if (comp < 500) {
                scaleFacLen[0] = ((comp - 400) >>> 2) / 5;
                scaleFacLen[1] = ((comp - 400) >>> 2) % 5;
                scaleFacLen[2] = (comp - 400) & 3;
                scaleFacLen[3] = 0;
                granule.preflag = false;
                lenType = 1;

            } else if (comp < 512) {
                scaleFacLen[0] = (comp - 500) / 3;
                scaleFacLen[1] = (comp - 500) % 3;
                scaleFacLen[2] = 0;
                scaleFacLen[3] = 0;
                granule.preflag = true;
                lenType = 2;
            }
        } else {
            int halfComp = comp >>> 1;

            if (halfComp < 180) {
                scaleFacLen[0] = halfComp / 36;
                scaleFacLen[1] = (halfComp % 36) / 6;
                scaleFacLen[2] = (halfComp % 36) % 6;
                scaleFacLen[3] = 0;
                granule.preflag = false;
                lenType = 3;
            } else if (halfComp < 244) {
                scaleFacLen[0] = ((halfComp - 180) & 0x3F) >>> 4;
                scaleFacLen[1] = ((halfComp - 180) & 0xF) >>> 2;
                scaleFacLen[2] = (halfComp - 180) & 3;
                scaleFacLen[3] = 0;
                granule.preflag = false;
                lenType = 4;
            } else if (halfComp < 255) {
                scaleFacLen[0] = (halfComp - 244) / 3;
                scaleFacLen[1] = (halfComp - 244) % 3;
                scaleFacLen[2] = 0;
                scaleFacLen[3] = 0;
                granule.preflag = false;
                lenType = 5;
            }
        }

        for (int i = 0, m = 0; i < 4; i++) {
            for (int j = 0; j < MpaConst.numberOfScaleFactors[lenType][blockType][i]; j++, m++) {
                result[m] = (scaleFacLen[i] == 0) ? 0 : br.readNBit(scaleFacLen[i]);
            }
        }

        return result;
    }

    static int readCoeffs(BitReader br, Granule granule, int ch, int part2_start, int sfreq, int[] out) {
        int part23End = part2_start + granule.part23Length;
        int region1Start = (sfreq == 8) ? 72 : 36;
        int region2Start = 576;

        if (!granule.windowSwitchingFlag || granule.blockType != 2) {
            int region1StartIdx = MathUtil.clip(granule.region0Count + granule.region1Count + 2, 0,
                    MpaConst.sfbLong[sfreq].length - 1);

            region1Start = MpaConst.sfbLong[sfreq][granule.region0Count + 1];
            region2Start = MpaConst.sfbLong[sfreq][region1StartIdx];
        }

        int index = 0;
        for (int i = 0; i < (granule.bigValues << 1); i += 2) {
            int tab = 0;
            if (i < region1Start)
                tab = granule.tableSelect[0];
            else if (i < region2Start)
                tab = granule.tableSelect[1];
            else
                tab = granule.tableSelect[2];
            if (tab == 0 || tab == 4 || tab == 14) {
                out[index++] = 0;
                out[index++] = 0;
            } else {
                int packed = readBigVal(tab, br);
                out[index++] = el16_0(packed);
                out[index++] = el16_1(packed);
            }
        }

        while (br.position() < part23End && index < 576) {

            int packed = readCount1(granule.count1tableSelect, br);

            out[index++] = el8_0(packed);
            out[index++] = el8_1(packed);
            out[index++] = el8_2(packed);
            out[index++] = el8_3(packed);
        }

        if (br.position() < part23End)
            br.readNBit(part23End - br.position());

        return MathUtil.clip(index, 0, 576);
    }

    static int readBigVal(int tab, BitReader br) {
        int res = bigValVlc[tab].readVLC(br);
        int x = res >>> 4;
        int y = res & 0xf;

        if (bigValEscBits[tab] != 0)
            if ((bigValMaxval[tab] - 1) == x)
                x += br.readNBit(bigValEscBits[tab]);
        if (x != 0)
            if (br.read1Bit() != 0)
                x = -x;
        if (bigValEscBits[tab] != 0)
            if ((bigValMaxval[tab] - 1) == y)
                y+= br.readNBit(bigValEscBits[tab]);
        if (y != 0)
            if (br.read1Bit() != 0)
                y = -y;
        return Vector2Int.pack16(x, y);
    }

    static int readCount1(int tab, BitReader br) {
        int res = (tab == 0 ? MpaConst.cnt1A : MpaConst.cnt1B).readVLC(br);

        int v = (res >> 3) & 1;
        int w = (res >> 2) & 1;
        int x = (res >> 1) & 1;
        int y = res & 1;

        if (v != 0)
            if (br.read1Bit() != 0)
                v = -v;
        if (w != 0)
            if (br.read1Bit() != 0)
                w = -w;
        if (x != 0)
            if (br.read1Bit() != 0)
                x = -x;
        if (y != 0)
            if (br.read1Bit() != 0)
                y = -y;
        return Vector4Int.pack8(v, w, x, y);
    }
}


package org.jcodec.codecs.mpeg12;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.List;

import org.jcodec.codecs.mpeg12.bitstream.PictureHeader;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.model.Packet.FrameType;
import org.jcodec.containers.mps.MPEGPacket;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 *
 * Pulls frames from MPEG elementary stream
 *
 * @author The JCodec project
 *
 */
public class MPEGES extends SegmentReader {

    private int frameNo;
    public long lastKnownDuration;

    public MPEGES(ReadableByteChannel channel, int fetchSize) throws IOException {
        super(channel, fetchSize);
    }

    /**
     * Reads one MPEG1/2 video frame from MPEG1/2 elementary stream into a
     * provided buffer.
     *
     * @param buffer
     *            A buffer to use for the data.
     * @return A packet with a video frame or null at for end of the stream. The
     *         data buffer inside the packet will be a sub-buffer of a 'buffer'
     *         provided as an argument.
     * @throws IOException
     */
    public MPEGPacket frame(ByteBuffer buffer) throws IOException {

        ByteBuffer dup = buffer.duplicate();

        while (curMarker != 0x100 && curMarker != 0x1b3 && skipToMarker())
            ;

        while (curMarker != 0x100 && readToNextMarker(dup))
            ;

        readToNextMarker(dup);

        while (curMarker != 0x100 && curMarker != 0x1b3 && readToNextMarker(dup))
            ;

        dup.flip();

        PictureHeader ph = MPEGDecoder.getPictureHeader(dup.duplicate());

        return dup.hasRemaining() ? new MPEGPacket(dup, 0, 90000, 0, frameNo++,
                ph.picture_coding_type <= MPEGConst.IntraCoded ? FrameType.KEY : FrameType.INTER, null) : null;
    }

    /**
     * Reads one MPEG1/2 video frame from MPEG1/2 elementary stream.
     *
     * @return A packet with a video frame or null at the end of stream.
     * @throws IOException
     */
    public MPEGPacket getFrame() throws IOException {

        while (curMarker != 0x100 && curMarker != 0x1b3 && skipToMarker())
            ;

        List<ByteBuffer> buffers = new ArrayList<ByteBuffer>();
        // Reading to the frame header, sequence header, sequence header
        // extensions and group header go in here
        while (curMarker != 0x100 && !done)
            readToNextMarkerBuffers(buffers);

        // Reading the frame header
        readToNextMarkerBuffers(buffers);

        // Reading the slices, will stop on encounter of a frame header of the
        // next frame or a sequence header
        while (curMarker != 0x100 && curMarker != 0x1b3 && !done)
            readToNextMarkerBuffers(buffers);

        ByteBuffer dup = NIOUtils.combineBuffers(buffers);
        PictureHeader ph = MPEGDecoder.getPictureHeader(dup.duplicate());

        return dup.hasRemaining() ? new MPEGPacket(dup, 0, 90000, 0, frameNo++,
                ph.picture_coding_type <= MPEGConst.IntraCoded ? FrameType.KEY : FrameType.INTER, null) : null;
    }
}


package net.sourceforge.jaad.aac;

import static net.sourceforge.jaad.aac.Profile.*;

import net.sourceforge.jaad.aac.syntax.BitStream;
import net.sourceforge.jaad.aac.syntax.SyntaxConstants;
import net.sourceforge.jaad.aac.syntax.IBitStream;
import net.sourceforge.jaad.aac.syntax.PCE;

/**
 * This class is part of JAAD ( jaadec.sourceforge.net ) that is distributed
 * under the Public Domain license. Code changes provided by the JCodec project
 * are distributed under FreeBSD license.
 *
 * AACDecoderConfig that must be passed to the
 * Decoder constructor. Typically it is created via one of the
 * static parsing methods.
 *
 * @author in-somnia
 */
public class AACDecoderConfig implements SyntaxConstants {

	private Profile profile, extProfile;
	private SampleFrequency sampleFrequency;
	private ChannelConfiguration channelConfiguration;
	private boolean frameLengthFlag;
	private boolean dependsOnCoreCoder;
	private int coreCoderDelay;
	private boolean extensionFlag;
	//extension: SBR
	private boolean sbrPresent, downSampledSBR, sbrEnabled;
	//extension: error resilience
	private boolean sectionDataResilience, scalefactorResilience, spectralDataResilience;

	private AACDecoderConfig() {
		profile = Profile.AAC_MAIN;
		extProfile = Profile.UNKNOWN;
		sampleFrequency = SampleFrequency.SAMPLE_FREQUENCY_NONE;
		channelConfiguration = ChannelConfiguration.CHANNEL_CONFIG_UNSUPPORTED;
		frameLengthFlag = false;
		sbrPresent = false;
		downSampledSBR = false;
		sbrEnabled = true;
		sectionDataResilience = false;
		scalefactorResilience = false;
		spectralDataResilience = false;
	}

	/* ========== gets/sets ========== */
	public ChannelConfiguration getChannelConfiguration() {
		return channelConfiguration;
	}

	public void setChannelConfiguration(ChannelConfiguration channelConfiguration) {
		this.channelConfiguration = channelConfiguration;
	}

	public int getCoreCoderDelay() {
		return coreCoderDelay;
	}

	public void setCoreCoderDelay(int coreCoderDelay) {
		this.coreCoderDelay = coreCoderDelay;
	}

	public boolean isDependsOnCoreCoder() {
		return dependsOnCoreCoder;
	}

	public void setDependsOnCoreCoder(boolean dependsOnCoreCoder) {
		this.dependsOnCoreCoder = dependsOnCoreCoder;
	}

	public Profile getExtObjectType() {
		return extProfile;
	}

	public void setExtObjectType(Profile extObjectType) {
		this.extProfile = extObjectType;
	}

	public int getFrameLength() {
		return frameLengthFlag ? WINDOW_SMALL_LEN_LONG : WINDOW_LEN_LONG;
	}

	public boolean isSmallFrameUsed() {
		return frameLengthFlag;
	}

	public void setSmallFrameUsed(boolean shortFrame) {
		this.frameLengthFlag = shortFrame;
	}

	public Profile getProfile() {
		return profile;
	}

	public void setProfile(Profile profile) {
		this.profile = profile;
	}

	public SampleFrequency getSampleFrequency() {
		return sampleFrequency;
	}

	public void setSampleFrequency(SampleFrequency sampleFrequency) {
		this.sampleFrequency = sampleFrequency;
	}

	//=========== SBR =============
	public boolean isSBRPresent() {
		return sbrPresent;
	}

	public boolean isSBRDownSampled() {
		return downSampledSBR;
	}

	public boolean isSBREnabled() {
		return sbrEnabled;
	}

	public void setSBREnabled(boolean enabled) {
		sbrEnabled = enabled;
	}

	//=========== ER =============
	public boolean isScalefactorResilienceUsed() {
		return scalefactorResilience;
	}

	public boolean isSectionDataResilienceUsed() {
		return sectionDataResilience;
	}

	public boolean isSpectralDataResilienceUsed() {
		return spectralDataResilience;
	}

	/* ======== static builder ========= */
	/**
	 * Parses the input arrays as a DecoderSpecificInfo, as used in MP4
	 * containers.
	 *
	 * @return a AACDecoderConfig
	 */
	public static AACDecoderConfig parseMP4DecoderSpecificInfo(byte[] data) throws AACException {
		final IBitStream _in = BitStream.createBitStream(data);
		final AACDecoderConfig config = new AACDecoderConfig();

		try {
			config.profile = readProfile(_in);

			int sf = _in.readBits(4);
			if(sf==0xF) config.sampleFrequency = SampleFrequency.forFrequency(_in.readBits(24));
			else config.sampleFrequency = SampleFrequency.forInt(sf);
			config.channelConfiguration = ChannelConfiguration.forInt(_in.readBits(4));

			Profile cp = config.profile;
			if (AAC_SBR == cp) {
                config.extProfile = cp;
                config.sbrPresent = true;
                sf = _in.readBits(4);
                //TODO: 24 bits already read; read again?
                //if(sf==0xF) config.sampleFrequency = SampleFrequency.forFrequency(_in.readBits(24));
                //if sample frequencies are the same: downsample SBR
                config.downSampledSBR = config.sampleFrequency.getIndex()==sf;
                config.sampleFrequency = SampleFrequency.forInt(sf);
                config.profile = readProfile(_in);
			} else if (AAC_MAIN == cp || AAC_LC ==  cp || AAC_SSR == cp || AAC_LTP == cp || ER_AAC_LC == cp || ER_AAC_LTP == cp || ER_AAC_LD == cp ) {
                //ga-specific info:
                config.frameLengthFlag = _in.readBool();
                if(config.frameLengthFlag) throw new AACException("config uses 960-sample frames, not yet supported"); //TODO: are 960-frames working yet?
                config.dependsOnCoreCoder = _in.readBool();
                if(config.dependsOnCoreCoder) config.coreCoderDelay = _in.readBits(14);
                else config.coreCoderDelay = 0;
                config.extensionFlag = _in.readBool();

                if(config.extensionFlag) {
                    if(cp.isErrorResilientProfile()) {
                        config.sectionDataResilience = _in.readBool();
                        config.scalefactorResilience = _in.readBool();
                        config.spectralDataResilience = _in.readBool();
                    }
                    //extensionFlag3
                    _in.skipBit();
                }

                if(config.channelConfiguration==ChannelConfiguration.CHANNEL_CONFIG_NONE) {
                    //TODO: is this working correct? -> ISO 14496-3 part 1: 1.A.4.3
                    _in.skipBits(3); //PCE
                    PCE pce = new PCE();
                    pce.decode(_in);
                    config.profile = pce.getProfile();
                    config.sampleFrequency = pce.getSampleFrequency();
                    config.channelConfiguration = ChannelConfiguration.forInt(pce.getChannelCount());
                }

                if(_in.getBitsLeft()>10) readSyncExtension(_in, config);
			} else {
                throw new AACException("profile not supported: "+cp.getIndex());
			}
			return config;
		}
		finally {
			_in.destroy();
		}
	}

	private static Profile readProfile(IBitStream _in) throws AACException {
		int i = _in.readBits(5);
		if(i==31) i = 32+_in.readBits(6);
		return Profile.forInt(i);
	}

	private static void readSyncExtension(IBitStream _in, AACDecoderConfig config) throws AACException {
		final int type = _in.readBits(11);
		switch(type) {
			case 0x2B7:
				final Profile profile = Profile.forInt(_in.readBits(5));

				if(profile.equals(Profile.AAC_SBR)) {
					config.sbrPresent = _in.readBool();
					if(config.sbrPresent) {
						config.profile = profile;

						int tmp = _in.readBits(4);

						if(tmp==config.sampleFrequency.getIndex()) config.downSampledSBR = true;
						if(tmp==15) {
							throw new AACException("sample rate specified explicitly, not supported yet!");
							//tmp = _in.readBits(24);
						}
					}
				}
				break;
		}
	}
}


package org.jcodec.codecs.common.biari;
import java.io.IOException;
import java.io.OutputStream;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 *
 * Binary ariphmetic encoder
 *
 * Half-way to MQ Coder
 *
 * @author The JCodec project
 *
 */
public class MQEncoder {
    public static final int CARRY_MASK = (1 << 27);

    // 'A' register, only lower 16 bits are used
    private int range;
    // 'C' register, only 28 bits are used
    private int offset;
    // 't' variable
    private int bitsToCode;
    // 'L' variable
    private long bytesOutput;
    // 'B' variable
    private int byteToGo;

    // Stream to output coded bytes
    private OutputStream out;

    public MQEncoder(OutputStream out) {
        range = 0x8000;
        offset = 0;
        bitsToCode = 12;
        this.out = out;
    }

    /**
     * Encodes one symbol either 0 or 1
     *
     * @param symbol
     * @throws IOException
     */
    public void encode(int symbol, Context cm) throws IOException {

        int rangeLps = MQConst.pLps[cm.getState()];
        if (symbol == cm.getMps()) {
            range -= rangeLps;
            offset += rangeLps;
            if (range < 0x8000) {
                while (range < 0x8000)
                    renormalize();
                cm.setState(MQConst.transitMPS[cm.getState()]);
            }
        } else {
            range = rangeLps;
            while (range < 0x8000)
                renormalize();

            if (MQConst.mpsSwitch[cm.getState()] != 0)
                cm.setMps(1 - cm.getMps());
            cm.setState(MQConst.transitLPS[cm.getState()]);
        }
    }

    public void finish() throws IOException {
        finalizeValue();
        offset <<= bitsToCode;

        int bitsToOutput = 12 - bitsToCode;
        outputByte();
        bitsToOutput -= bitsToCode;
        if (bitsToOutput > 0) {
            offset <<= bitsToCode;
            outputByte();
        }

        out.write(byteToGo);
    }

    private void finalizeValue() {
        int halfBit = offset & 0x8000;
        offset &= 0xffff0000;
        if (halfBit == 0) {
            offset |= 0x8000;
        } else {
            offset += 0x10000;
        }
    }

    private void renormalize() throws IOException {

        offset <<= 1;
        range <<= 1;
        range &= 0xffffL;

        --bitsToCode;

        if (bitsToCode == 0)
            outputByte();
    }

    private void outputByte() throws IOException {
        if (bytesOutput == 0)
            outputByteNoStuffing();
        else {
            if (byteToGo == 0xff)
                outputByteWithStuffing();
            else {
                if ((offset & CARRY_MASK) != 0) {
                    ++byteToGo;
                    offset &= 0x7ffffff;
                    if (byteToGo == 0xff)
                        outputByteWithStuffing();
                    else
                        outputByteNoStuffing();
                } else
                    outputByteNoStuffing();
            }
        }
    }

    private void outputByteWithStuffing() throws IOException {
        bitsToCode = 7;
        if (bytesOutput > 0) {
            out.write(byteToGo);
        }
        byteToGo = (offset >> 20) & 0xff;
        offset &= 0xfffff;

        ++bytesOutput;
    }

    private void outputByteNoStuffing() throws IOException {
        bitsToCode = 8;
        if (bytesOutput > 0) {
            out.write(byteToGo);
        }
        byteToGo = (offset >> 19) & 0xff;

        offset &= 0x7ffff;

        ++bytesOutput;
    }
}


package org.jcodec.codecs.h264.decode;
import static org.jcodec.codecs.h264.io.model.SeqParameterSet.getPicHeightInMbs;
import static org.jcodec.codecs.h264.decode.CAVLCReader.readBool;
import static org.jcodec.codecs.h264.decode.CAVLCReader.readSE;
import static org.jcodec.codecs.h264.decode.CAVLCReader.readU;
import static org.jcodec.codecs.h264.decode.CAVLCReader.readUEtrace;
import static org.jcodec.common.model.ColorSpace.MONO;

import org.jcodec.codecs.h264.io.model.NALUnit;
import org.jcodec.codecs.h264.io.model.NALUnitType;
import org.jcodec.codecs.h264.io.model.PictureParameterSet;
import org.jcodec.codecs.h264.io.model.PredictionWeightTable;
import org.jcodec.codecs.h264.io.model.RefPicMarking;
import org.jcodec.codecs.h264.io.model.RefPicMarking.InstrType;
import org.jcodec.codecs.h264.io.model.RefPicMarking.Instruction;
import org.jcodec.codecs.h264.io.model.RefPicMarkingIDR;
import org.jcodec.codecs.h264.io.model.SeqParameterSet;
import org.jcodec.codecs.h264.io.model.SliceHeader;
import org.jcodec.codecs.h264.io.model.SliceType;
import org.jcodec.common.IntArrayList;
import org.jcodec.common.io.BitReader;

import java.util.ArrayList;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 *
 * Reads header of the coded slice
 *
 * @author The JCodec project
 *
 */
public class SliceHeaderReader {
    private SliceHeaderReader() {
    }

    public static SliceHeader readPart1(BitReader _in) {

        SliceHeader sh = new SliceHeader();
        sh.firstMbInSlice = readUEtrace(_in, "SH: first_mb_in_slice");
        int shType = readUEtrace(_in, "SH: slice_type");
        sh.sliceType = SliceType.fromValue(shType % 5);
        sh.sliceTypeRestr = (shType / 5) > 0;

        sh.picParameterSetId = readUEtrace(_in, "SH: pic_parameter_set_id");

        return sh;
    }

    public static SliceHeader readPart2(SliceHeader sh, NALUnit nalUnit, SeqParameterSet sps, PictureParameterSet pps,
            BitReader _in) {
        sh.pps = pps;
        sh.sps = sps;

        sh.frameNum = readU(_in, sps.log2MaxFrameNumMinus4 + 4, "SH: frame_num");
        if (!sps.frameMbsOnlyFlag) {
            sh.fieldPicFlag = readBool(_in, "SH: field_pic_flag");
            if (sh.fieldPicFlag) {
                sh.bottomFieldFlag = readBool(_in, "SH: bottom_field_flag");
            }
        }
        if (nalUnit.type == NALUnitType.IDR_SLICE) {
            sh.idrPicId = readUEtrace(_in, "SH: idr_pic_id");
        }
        if (sps.picOrderCntType == 0) {
            sh.picOrderCntLsb = readU(_in, sps.log2MaxPicOrderCntLsbMinus4 + 4, "SH: pic_order_cnt_lsb");
            if (pps.picOrderPresentFlag && !sps.fieldPicFlag) {
                sh.deltaPicOrderCntBottom = readSE(_in, "SH: delta_pic_order_cnt_bottom");
            }
        }
        sh.deltaPicOrderCnt = new int[2];
        if (sps.picOrderCntType == 1 && !sps.deltaPicOrderAlwaysZeroFlag) {
            sh.deltaPicOrderCnt[0] = readSE(_in, "SH: delta_pic_order_cnt[0]");
            if (pps.picOrderPresentFlag && !sps.fieldPicFlag)
                sh.deltaPicOrderCnt[1] = readSE(_in, "SH: delta_pic_order_cnt[1]");
        }
        if (pps.redundantPicCntPresentFlag) {
            sh.redundantPicCnt = readUEtrace(_in, "SH: redundant_pic_cnt");
        }
        if (sh.sliceType == SliceType.B) {
            sh.directSpatialMvPredFlag = readBool(_in, "SH: direct_spatial_mv_pred_flag");
        }
        if (sh.sliceType == SliceType.P || sh.sliceType == SliceType.SP || sh.sliceType == SliceType.B) {
            sh.numRefIdxActiveOverrideFlag = readBool(_in, "SH: num_ref_idx_active_override_flag");
            if (sh.numRefIdxActiveOverrideFlag) {
                sh.numRefIdxActiveMinus1[0] = readUEtrace(_in, "SH: num_ref_idx_l0_active_minus1");
                if (sh.sliceType == SliceType.B) {
                    sh.numRefIdxActiveMinus1[1] = readUEtrace(_in, "SH: num_ref_idx_l1_active_minus1");
                }
            }
        }
        readRefPicListReordering(sh, _in);
        if ((pps.weightedPredFlag && (sh.sliceType == SliceType.P || sh.sliceType == SliceType.SP))
                || (pps.weightedBipredIdc == 1 && sh.sliceType == SliceType.B))
            readPredWeightTable(sps, pps, sh, _in);
        if (nalUnit.nal_ref_idc != 0)
            readDecoderPicMarking(nalUnit, sh, _in);
        if (pps.entropyCodingModeFlag && sh.sliceType.isInter()) {
            sh.cabacInitIdc = readUEtrace(_in, "SH: cabac_init_idc");
        }
        sh.sliceQpDelta = readSE(_in, "SH: slice_qp_delta");
        if (sh.sliceType == SliceType.SP || sh.sliceType == SliceType.SI) {
            if (sh.sliceType == SliceType.SP) {
                sh.spForSwitchFlag = readBool(_in, "SH: sp_for_switch_flag");
            }
            sh.sliceQsDelta = readSE(_in, "SH: slice_qs_delta");
        }
        if (pps.deblockingFilterControlPresentFlag) {
            sh.disableDeblockingFilterIdc = readUEtrace(_in, "SH: disable_deblocking_filter_idc");
            if (sh.disableDeblockingFilterIdc != 1) {
                sh.sliceAlphaC0OffsetDiv2 = readSE(_in, "SH: slice_alpha_c0_offset_div2");
                sh.sliceBetaOffsetDiv2 = readSE(_in, "SH: slice_beta_offset_div2");
            }
        }
        if (pps.numSliceGroupsMinus1 > 0 && pps.sliceGroupMapType >= 3 && pps.sliceGroupMapType <= 5) {
            int len = getPicHeightInMbs(sps) * (sps.picWidthInMbsMinus1 + 1)
                    / (pps.sliceGroupChangeRateMinus1 + 1);
            if ((getPicHeightInMbs(sps) * (sps.picWidthInMbsMinus1 + 1))
                    % (pps.sliceGroupChangeRateMinus1 + 1) > 0)
                len += 1;

            len = CeilLog2(len + 1);
            sh.sliceGroupChangeCycle = readU(_in, len, "SH: slice_group_change_cycle");
        }

        return sh;
    }

    private static int CeilLog2(int uiVal) {
        int uiTmp = uiVal - 1;
        int uiRet = 0;

        while (uiTmp != 0) {
            uiTmp >>= 1;
            uiRet++;
        }
        return uiRet;
    }

    // static int i = 0;

    private static void readDecoderPicMarking(NALUnit nalUnit, SliceHeader sh, BitReader _in) {
        if (nalUnit.type == NALUnitType.IDR_SLICE) {
            boolean noOutputOfPriorPicsFlag = readBool(_in, "SH: no_output_of_prior_pics_flag");
            boolean longTermReferenceFlag = readBool(_in, "SH: long_term_reference_flag");
            sh.refPicMarkingIDR = new RefPicMarkingIDR(noOutputOfPriorPicsFlag, longTermReferenceFlag);
        } else {
            boolean adaptiveRefPicMarkingModeFlag = readBool(_in, "SH: adaptive_ref_pic_marking_mode_flag");
            if (adaptiveRefPicMarkingModeFlag) {
                ArrayList<Instruction> mmops = new ArrayList<Instruction>();
                int memoryManagementControlOperation;
                do {
                    memoryManagementControlOperation = readUEtrace(_in, "SH: memory_management_control_operation");

                    Instruction instr = null;

                    switch (memoryManagementControlOperation) {
                    case 1:
                        instr = new RefPicMarking.Instruction(InstrType.REMOVE_SHORT, readUEtrace(_in,
                                "SH: difference_of_pic_nums_minus1") + 1, 0);
                        break;
                    case 2:
                        instr = new RefPicMarking.Instruction(InstrType.REMOVE_LONG,
                                readUEtrace(_in, "SH: long_term_pic_num"), 0);
                        break;
                    case 3:
                        instr = new RefPicMarking.Instruction(InstrType.CONVERT_INTO_LONG, readUEtrace(_in,
                                "SH: difference_of_pic_nums_minus1") + 1, readUEtrace(_in, "SH: long_term_frame_idx"));
                        break;
                    case 4:
                        instr = new RefPicMarking.Instruction(InstrType.TRUNK_LONG, readUEtrace(_in,
                                "SH: max_long_term_frame_idx_plus1") - 1, 0);
                        break;
                    case 5:
                        instr = new RefPicMarking.Instruction(InstrType.CLEAR, 0, 0);
                        break;
                    case 6:
                        instr = new RefPicMarking.Instruction(InstrType.MARK_LONG,
                                readUEtrace(_in, "SH: long_term_frame_idx"), 0);
                        break;
                    }
                    if (instr != null)
                        mmops.add(instr);
                } while (memoryManagementControlOperation != 0);
                sh.refPicMarkingNonIDR = new RefPicMarking(mmops.toArray(new Instruction[] {}));
            }
        }
    }

    private static void readPredWeightTable(SeqParameterSet sps, PictureParameterSet pps, SliceHeader sh, BitReader _in) {
        sh.predWeightTable = new PredictionWeightTable();
        int[] numRefsMinus1 = sh.numRefIdxActiveOverrideFlag ? sh.numRefIdxActiveMinus1
                : pps.numRefIdxActiveMinus1;
        int[] nr = new int[] {numRefsMinus1[0] + 1, numRefsMinus1[1] + 1};

        sh.predWeightTable.lumaLog2WeightDenom = readUEtrace(_in, "SH: luma_log2_weight_denom");
        if (sps.chromaFormatIdc != MONO) {
            sh.predWeightTable.chromaLog2WeightDenom = readUEtrace(_in, "SH: chroma_log2_weight_denom");
        }
        int defaultLW = 1 << sh.predWeightTable.lumaLog2WeightDenom;
        int defaultCW = 1 << sh.predWeightTable.chromaLog2WeightDenom;

        for (int list = 0; list < 2; list++) {
            sh.predWeightTable.lumaWeight[list] = new int[nr[list]];
            sh.predWeightTable.lumaOffset[list] = new int[nr[list]];
            sh.predWeightTable.chromaWeight[list] = new int[2][nr[list]];
            sh.predWeightTable.chromaOffset[list] = new int[2][nr[list]];
            for (int i = 0; i < nr[list]; i++) {
                sh.predWeightTable.lumaWeight[list][i] = defaultLW;
                sh.predWeightTable.lumaOffset[list][i] = 0;
                sh.predWeightTable.chromaWeight[list][0][i] = defaultCW;
                sh.predWeightTable.chromaOffset[list][0][i] = 0;
                sh.predWeightTable.chromaWeight[list][1][i] = defaultCW;
                sh.predWeightTable.chromaOffset[list][1][i] = 0;
            }
        }

        readWeightOffset(sps, pps, sh, _in, nr, 0);
        if (sh.sliceType == SliceType.B) {
            readWeightOffset(sps, pps, sh, _in, nr, 1);
        }
    }

    private static void readWeightOffset(SeqParameterSet sps, PictureParameterSet pps, SliceHeader sh, BitReader _in,
            int[] numRefs, int list) {

        for (int i = 0; i < numRefs[list]; i++) {
            boolean lumaWeightL0Flag = readBool(_in, "SH: luma_weight_l0_flag");
            if (lumaWeightL0Flag) {
                sh.predWeightTable.lumaWeight[list][i] = readSE(_in, "SH: weight");
                sh.predWeightTable.lumaOffset[list][i] = readSE(_in, "SH: offset");
            }
            if (sps.chromaFormatIdc != MONO) {
                boolean chromaWeightL0Flag = readBool(_in, "SH: chroma_weight_l0_flag");
                if (chromaWeightL0Flag) {
                    sh.predWeightTable.chromaWeight[list][0][i] = readSE(_in, "SH: weight");
                    sh.predWeightTable.chromaOffset[list][0][i] = readSE(_in, "SH: offset");
                    sh.predWeightTable.chromaWeight[list][1][i] = readSE(_in, "SH: weight");
                    sh.predWeightTable.chromaOffset[list][1][i] = readSE(_in, "SH: offset");
                }
            }
        }
    }

    private static void readRefPicListReordering(SliceHeader sh, BitReader _in) {
        sh.refPicReordering = new int[2][][];
        // System.out.println(i++);
        if (sh.sliceType.isInter()) {
            boolean refPicListReorderingFlagL0 = readBool(_in, "SH: ref_pic_list_reordering_flag_l0");
            if (refPicListReorderingFlagL0) {
                sh.refPicReordering[0] = readReorderingEntries(_in);
            }
        }
        if (sh.sliceType == SliceType.B) {
            boolean refPicListReorderingFlagL1 = readBool(_in, "SH: ref_pic_list_reordering_flag_l1");
            if (refPicListReorderingFlagL1) {
                sh.refPicReordering[1] = readReorderingEntries(_in);
            }
        }
    }

    private static int[][] readReorderingEntries(BitReader _in) {
        IntArrayList ops = IntArrayList.createIntArrayList();
        IntArrayList args = IntArrayList.createIntArrayList();
        do {
            int idc = readUEtrace(_in, "SH: reordering_of_pic_nums_idc");
            if (idc == 3)
                break;
            ops.add(idc);
            args.add(readUEtrace(_in, "SH: abs_diff_pic_num_minus1"));
        } while (true);
        return new int[][] { ops.toArray(), args.toArray() };
    }
}