package org.jcodec.common; import org.jcodec.common.io.NIOUtils; import java.nio.ByteBuffer; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * @author The JCodec project * */ public abstract class RunLength { protected IntArrayList counts; public RunLength() { this.counts = IntArrayList.createIntArrayList(); } public int estimateSize() { int[] counts = getCounts(); int recCount = 0; for (int i = 0; i < counts.length; i++, recCount++) { int count = counts[i]; while (count >= 0x100) { ++recCount; count -= 0x100; } } return recCount * recSize() + 4; } protected abstract int recSize(); protected abstract void finish(); public int[] getCounts() { finish(); return counts.toArray(); } public static class Integer extends RunLength { private static final int MIN_VALUE = java.lang.Integer.MIN_VALUE; private int lastValue; private int count = 0; private IntArrayList values; public Integer() { super(); this.lastValue = Integer.MIN_VALUE; this.values = IntArrayList.createIntArrayList(); } public void add(int value) { if (lastValue == Integer.MIN_VALUE || lastValue != value) { if (lastValue != Integer.MIN_VALUE) { values.add(lastValue); counts.add(count); count = 0; } lastValue = value; } ++count; } public int[] getValues() { finish(); return values.toArray(); } protected void finish() { if (lastValue != Integer.MIN_VALUE) { values.add(lastValue); counts.add(count); lastValue = Integer.MIN_VALUE; count = 0; } } public void serialize(ByteBuffer bb) { ByteBuffer dup = bb.duplicate(); int[] counts = getCounts(); int[] values = getValues(); NIOUtils.skip(bb, 4); int recCount = 0; for (int i = 0; i < counts.length; i++, recCount++) { int count = counts[i]; while (count >= 0x100) { bb.put((byte) 0xff); bb.putInt(values[i]); ++recCount; count -= 0x100; } bb.put((byte) (count - 1)); bb.putInt(values[i]); } dup.putInt(recCount); } public static RunLength.Integer parse(ByteBuffer bb) { RunLength.Integer rl = new RunLength.Integer(); int recCount = bb.getInt(); for (int i = 0; i < recCount; i++) { int count = (bb.get() & 0xff) + 1; int value = bb.getInt(); rl.counts.add(count); rl.values.add(value); } return rl; } protected int recSize() { return 5; } public int[] flattern() { int[] counts = getCounts(); int total = 0; for (int i = 0; i < counts.length; i++) { total += counts[i]; } int[] values = getValues(); int[] result = new int[total]; for (int i = 0, ind = 0; i < counts.length; i++) { for (int j = 0; j < counts[i]; j++, ind++) result[ind] = values[i]; } return result; } } public static class Long extends RunLength { private static final long MIN_VALUE = java.lang.Long.MIN_VALUE; private long lastValue; private int count = 0; private LongArrayList values; public Long() { super(); this.lastValue = Long.MIN_VALUE; this.values = LongArrayList.createLongArrayList(); } public void add(long value) { if (lastValue == Long.MIN_VALUE || lastValue != value) { if (lastValue != Long.MIN_VALUE) { values.add(lastValue); counts.add(count); count = 0; } lastValue = value; } ++count; } public int[] getCounts() { finish(); return counts.toArray(); } public long[] getValues() { finish(); return values.toArray(); } protected void finish() { if (lastValue != Long.MIN_VALUE) { values.add(lastValue); counts.add(count); lastValue = Long.MIN_VALUE; count = 0; } } public void serialize(ByteBuffer bb) { ByteBuffer dup = bb.duplicate(); int[] counts = getCounts(); long[] values = getValues(); NIOUtils.skip(bb, 4); int recCount = 0; for (int i = 0; i < counts.length; i++, recCount++) { int count = counts[i]; while (count >= 0x100) { bb.put((byte) 0xff); bb.putLong(values[i]); ++recCount; count -= 0x100; } bb.put((byte) (count - 1)); bb.putLong(values[i]); } dup.putInt(recCount); } public static RunLength.Long parse(ByteBuffer bb) { RunLength.Long rl = new RunLength.Long(); int recCount = bb.getInt(); for (int i = 0; i < recCount; i++) { int count = (bb.get() & 0xff) + 1; long value = bb.getLong(); rl.counts.add(count); rl.values.add(value); } return rl; } @Override protected int recSize() { return 9; } public long[] flattern() { int[] counts = getCounts(); int total = 0; for (int i = 0; i < counts.length; i++) { total += counts[i]; } long[] values = getValues(); long[] result = new long[total]; for (int i = 0, ind = 0; i < counts.length; i++) { for (int j = 0; j < counts[i]; j++, ind++) result[ind] = values[i]; } return result; } } }